mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
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/12890 Reviewed-by: Ian Lance Taylor <iant@golang.org> Reviewed-by: Rob Pike <r@golang.org>
This commit is contained in:
parent
bfac8623d5
commit
c4092ac398
4 changed files with 68 additions and 3 deletions
|
|
@ -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{}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const PtrSize = ptrSize
|
const PtrSize = ptrSize
|
||||||
|
|
||||||
|
var TestingAssertE2I2GC = &testingAssertE2I2GC
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
||||||
}
|
}
|
||||||
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 @@
|
||||||
|
|
||||||
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) {
|
||||||
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 {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue