cmd/compile: guard against loads with negative offset from readonly constants

CL 154057 adds guards agaist out-of-bound reads from readonly
constants. It turns out that in dead code, the offset can also
be negative. Guard against negative offset as well.

Fixes #30257.

Change-Id: I47c2a2e434dd466c08ae6f50f213999a358c796e
Reviewed-on: https://go-review.googlesource.com/c/162819
Reviewed-by: Keith Randall <khr@golang.org>
diff --git a/src/cmd/compile/internal/ssa/rewrite.go b/src/cmd/compile/internal/ssa/rewrite.go
index 6edb593..9c9de75 100644
--- a/src/cmd/compile/internal/ssa/rewrite.go
+++ b/src/cmd/compile/internal/ssa/rewrite.go
@@ -1142,7 +1142,7 @@
 // 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)) {
+	if off >= int64(len(lsym.P)) || off < 0 {
 		// 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.
@@ -1155,7 +1155,7 @@
 // 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 {
+	if off >= int64(len(lsym.P))-1 || off < 0 {
 		return 0
 	}
 	if bigEndian {
@@ -1168,7 +1168,7 @@
 // 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 {
+	if off >= int64(len(lsym.P))-3 || off < 0 {
 		return 0
 	}
 	if bigEndian {
@@ -1181,7 +1181,7 @@
 // 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 {
+	if off >= int64(len(lsym.P))-7 || off < 0 {
 		return 0
 	}
 	if bigEndian {
diff --git a/test/fixedbugs/issue29215.go b/test/fixedbugs/issue29215.go
index df703aa..4e8f107 100644
--- a/test/fixedbugs/issue29215.go
+++ b/test/fixedbugs/issue29215.go
@@ -16,3 +16,20 @@
         }
         _ = s == "bbb"
 }
+
+// Another case: load from negative offset of a symbol
+// in dead code (issue 30257).
+func g() {
+	var i int
+	var s string
+
+	if true {
+		s = "a"
+	}
+
+	if f := 0.0; -f < 0 {
+		i = len(s[:4])
+	}
+
+	_ = s[i-1:0] != "bb" && true
+}