]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: ignore out-of-bounds reads from readonly constants
authorKeith Randall <keithr@alum.mit.edu>
Thu, 13 Dec 2018 17:31:21 +0000 (09:31 -0800)
committerKeith Randall <khr@golang.org>
Thu, 20 Dec 2018 17:34:32 +0000 (17:34 +0000)
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 <khr@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Alberto Donizetti <alb.donizetti@gmail.com>
src/cmd/compile/internal/ssa/rewrite.go
test/fixedbugs/issue29215.go [new file with mode: 0644]

index 1fd335b3e7f0c5968326fd748211592243be4900..69365c4e6066b2fc065bc326c76d504b9f83f1c6 100644 (file)
@@ -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 (file)
index 0000000..df703aa
--- /dev/null
@@ -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"
+}