Commit c4092ac3 authored by Russ Cox's avatar Russ Cox

cmd/compile: fix uninitialized memory during type switch assertE2I2

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/12890Reviewed-by: default avatarIan Lance Taylor <iant@golang.org>
Reviewed-by: default avatarRob Pike <r@golang.org>
parent bfac8623
...@@ -652,6 +652,9 @@ func (s *typeSwitch) typeone(t *Node) *Node { ...@@ -652,6 +652,9 @@ func (s *typeSwitch) typeone(t *Node) *Node {
} else { } else {
name = t.Rlist.N name = t.Rlist.N
init = list1(Nod(ODCL, name, nil)) init = list1(Nod(ODCL, name, nil))
a := Nod(OAS, name, nil)
typecheck(&a, Etop)
init = list(init, a)
} }
a := Nod(OAS2, nil, nil) a := Nod(OAS2, nil, nil)
......
...@@ -152,3 +152,5 @@ func BenchSetType(n int, x interface{}) { ...@@ -152,3 +152,5 @@ func BenchSetType(n int, x interface{}) {
} }
const PtrSize = ptrSize const PtrSize = ptrSize
var TestingAssertE2I2GC = &testingAssertE2I2GC
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
package runtime_test package runtime_test
import ( import (
"io"
"os" "os"
"reflect" "reflect"
"runtime" "runtime"
...@@ -412,3 +413,59 @@ func TestPrintGC(t *testing.T) { ...@@ -412,3 +413,59 @@ func TestPrintGC(t *testing.T) {
} }
close(done) 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
}
...@@ -4,9 +4,7 @@ ...@@ -4,9 +4,7 @@
package runtime package runtime
import ( import "unsafe"
"unsafe"
)
const ( const (
hashSize = 1009 hashSize = 1009
...@@ -356,7 +354,12 @@ func assertE2I(inter *interfacetype, e interface{}, r *fInterface) { ...@@ -356,7 +354,12 @@ func assertE2I(inter *interfacetype, e interface{}, r *fInterface) {
rp.data = ep.data rp.data = ep.data
} }
var testingAssertE2I2GC bool
func assertE2I2(inter *interfacetype, e interface{}, r *fInterface) bool { func assertE2I2(inter *interfacetype, e interface{}, r *fInterface) bool {
if testingAssertE2I2GC {
GC()
}
ep := (*eface)(unsafe.Pointer(&e)) ep := (*eface)(unsafe.Pointer(&e))
t := ep._type t := ep._type
if t == nil { if t == nil {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment