]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: fix uninitialized memory during type switch assertE2I2
authorRuss Cox <rsc@golang.org>
Thu, 30 Jul 2015 04:46:42 +0000 (00:46 -0400)
committerRuss Cox <rsc@golang.org>
Thu, 30 Jul 2015 05:21:56 +0000 (05:21 +0000)
Fixes arm64 builder crash.

The bug is possible on all architectures; you just have to get lucky
and hit a preemption or a stack growth on entry to assertE2I2.
The test stacks the deck.

Change-Id: I8419da909b06249b1ad15830cbb64e386b6aa5f6
Reviewed-on: https://go-review.googlesource.com/12890
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
src/cmd/compile/internal/gc/swt.go
src/runtime/export_test.go
src/runtime/gc_test.go
src/runtime/iface.go

index a736208340b72580587d118df7bafaeac756e26a..f34b1c614c8ed8df5d67aa47f5319a331121c8fb 100644 (file)
@@ -652,6 +652,9 @@ func (s *typeSwitch) typeone(t *Node) *Node {
        } else {
                name = t.Rlist.N
                init = list1(Nod(ODCL, name, nil))
+               a := Nod(OAS, name, nil)
+               typecheck(&a, Etop)
+               init = list(init, a)
        }
 
        a := Nod(OAS2, nil, nil)
index 3fddcc868f2a0ba9c5548a7eab10c6a6cd53c2b4..16d54765b7e967ea61c981aa1c3fdc5a4eacd2a4 100644 (file)
@@ -152,3 +152,5 @@ func BenchSetType(n int, x interface{}) {
 }
 
 const PtrSize = ptrSize
+
+var TestingAssertE2I2GC = &testingAssertE2I2GC
index e3e0c3a5836c0ca1ee6e93381c80e62c623b0f88..636e5248c8b1d117d9b0378dfa423d1d6c08a02c 100644 (file)
@@ -5,6 +5,7 @@
 package runtime_test
 
 import (
+       "io"
        "os"
        "reflect"
        "runtime"
@@ -412,3 +413,59 @@ func TestPrintGC(t *testing.T) {
        }
        close(done)
 }
+
+// The implicit y, ok := x.(error) for the case error
+// in testTypeSwitch used to not initialize the result y
+// before passing &y to assertE2I2GC.
+// Catch this by making assertE2I2 call runtime.GC,
+// which will force a stack scan and failure if there are
+// bad pointers, and then fill the stack with bad pointers
+// and run the type switch.
+func TestAssertE2I2Liveness(t *testing.T) {
+       // Note that this flag is defined in export_test.go
+       // and is not available to ordinary imports of runtime.
+       *runtime.TestingAssertE2I2GC = true
+       defer func() {
+               *runtime.TestingAssertE2I2GC = false
+       }()
+
+       poisonStack()
+       testTypeSwitch(io.EOF)
+       poisonStack()
+       testAssert(io.EOF)
+       poisonStack()
+       testAssertVar(io.EOF)
+}
+
+func poisonStack() uintptr {
+       var x [1000]uintptr
+       for i := range x {
+               x[i] = 0xff
+       }
+       return x[123]
+}
+
+func testTypeSwitch(x interface{}) error {
+       switch y := x.(type) {
+       case nil:
+               // ok
+       case error:
+               return y
+       }
+       return nil
+}
+
+func testAssert(x interface{}) error {
+       if y, ok := x.(error); ok {
+               return y
+       }
+       return nil
+}
+
+func testAssertVar(x interface{}) error {
+       var y, ok = x.(error)
+       if ok {
+               return y
+       }
+       return nil
+}
index 656bb4b8e5c227d74541be12b8e9dcccb55201bc..abd7068ed1afcb9f4e7f57b7b5d72df5d34d3fff 100644 (file)
@@ -4,9 +4,7 @@
 
 package runtime
 
-import (
-       "unsafe"
-)
+import "unsafe"
 
 const (
        hashSize = 1009
@@ -356,7 +354,12 @@ func assertE2I(inter *interfacetype, e interface{}, r *fInterface) {
        rp.data = ep.data
 }
 
+var testingAssertE2I2GC bool
+
 func assertE2I2(inter *interfacetype, e interface{}, r *fInterface) bool {
+       if testingAssertE2I2GC {
+               GC()
+       }
        ep := (*eface)(unsafe.Pointer(&e))
        t := ep._type
        if t == nil {