From 443990742ec6dd128fab41d4afaa8668e665eadd Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Thu, 13 Dec 2018 09:31:21 -0800 Subject: [PATCH] cmd/compile: ignore out-of-bounds reads from readonly constants Out-of-bounds reads of globals can happen in dead code. For code like this: s := "a" if len(s) == 3 { load s[0], s[1], and s[2] } The out-of-bounds loads are dead code, but aren't removed yet when lowering. We need to not panic when compile-time evaluating those loads. This can only happen for dead code, so the result doesn't matter. Fixes #29215 Change-Id: I7fb765766328b9524c6f2a1e6ab8d8edd9875097 Reviewed-on: https://go-review.googlesource.com/c/154057 Run-TryBot: Keith Randall TryBot-Result: Gobot Gobot Reviewed-by: Alberto Donizetti --- src/cmd/compile/internal/ssa/rewrite.go | 16 ++++++++++++++++ test/fixedbugs/issue29215.go | 18 ++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 test/fixedbugs/issue29215.go diff --git a/src/cmd/compile/internal/ssa/rewrite.go b/src/cmd/compile/internal/ssa/rewrite.go index 1fd335b3e7..69365c4e60 100644 --- a/src/cmd/compile/internal/ssa/rewrite.go +++ b/src/cmd/compile/internal/ssa/rewrite.go @@ -1137,12 +1137,22 @@ func symIsRO(sym interface{}) bool { // read8 reads one byte from the read-only global sym at offset off. func read8(sym interface{}, off int64) uint8 { lsym := sym.(*obj.LSym) + if off >= int64(len(lsym.P)) { + // Invalid index into the global sym. + // This can happen in dead code, so we don't want to panic. + // Just return any value, it will eventually get ignored. + // See issue 29215. + return 0 + } return lsym.P[off] } // read16 reads two bytes from the read-only global sym at offset off. func read16(sym interface{}, off int64, bigEndian bool) uint16 { lsym := sym.(*obj.LSym) + if off >= int64(len(lsym.P))-1 { + return 0 + } if bigEndian { return binary.BigEndian.Uint16(lsym.P[off:]) } else { @@ -1153,6 +1163,9 @@ func read16(sym interface{}, off int64, bigEndian bool) uint16 { // read32 reads four bytes from the read-only global sym at offset off. func read32(sym interface{}, off int64, bigEndian bool) uint32 { lsym := sym.(*obj.LSym) + if off >= int64(len(lsym.P))-3 { + return 0 + } if bigEndian { return binary.BigEndian.Uint32(lsym.P[off:]) } else { @@ -1163,6 +1176,9 @@ func read32(sym interface{}, off int64, bigEndian bool) uint32 { // read64 reads eight bytes from the read-only global sym at offset off. func read64(sym interface{}, off int64, bigEndian bool) uint64 { lsym := sym.(*obj.LSym) + if off >= int64(len(lsym.P))-7 { + return 0 + } if bigEndian { return binary.BigEndian.Uint64(lsym.P[off:]) } else { diff --git a/test/fixedbugs/issue29215.go b/test/fixedbugs/issue29215.go new file mode 100644 index 0000000000..df703aa25d --- /dev/null +++ b/test/fixedbugs/issue29215.go @@ -0,0 +1,18 @@ +// compile + +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +func f() { + var s string + var p, q bool + s = "a" + for p { + p = false == (true != q) + s = "" + } + _ = s == "bbb" +}