From: Austin Clements Date: Mon, 24 Aug 2015 17:35:49 +0000 (-0400) Subject: cmd/compile: fix uninitialized memory in compare of interface value X-Git-Tag: go1.6beta1~1275 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=05a3b1fce56a95e40512bae9f62656098f198834;p=gostls13.git cmd/compile: fix uninitialized memory in compare of interface value A comparison of the form l == r where l is an interface and r is concrete performs a type assertion on l to convert it to r's type. However, the compiler fails to zero the temporary where the result of the type assertion is written, so if the type is a pointer type and a stack scan occurs while in the type assertion, it may see an invalid pointer on the stack. Fix this by zeroing the temporary. This is equivalent to the fix for type switches from c4092ac. Fixes #12253. Change-Id: Iaf205d456b856c056b317b4e888ce892f0c555b9 Reviewed-on: https://go-review.googlesource.com/13872 Reviewed-by: Russ Cox --- diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go index ce73018b8b..af3e1ccbe4 100644 --- a/src/cmd/compile/internal/gc/walk.go +++ b/src/cmd/compile/internal/gc/walk.go @@ -3219,6 +3219,11 @@ func walkcompare(np **Node, init **NodeList) { if l != nil { x := temp(r.Type) + if haspointers(r.Type) { + a := Nod(OAS, x, nil) + typecheck(&a, Etop) + *init = list(*init, a) + } ok := temp(Types[TBOOL]) // l.(type(r)) diff --git a/src/runtime/export_test.go b/src/runtime/export_test.go index 16d54765b7..f14dc30a7f 100644 --- a/src/runtime/export_test.go +++ b/src/runtime/export_test.go @@ -154,3 +154,4 @@ func BenchSetType(n int, x interface{}) { const PtrSize = ptrSize var TestingAssertE2I2GC = &testingAssertE2I2GC +var TestingAssertE2T2GC = &testingAssertE2T2GC diff --git a/src/runtime/gc_test.go b/src/runtime/gc_test.go index 636e5248c8..6c9b314c65 100644 --- a/src/runtime/gc_test.go +++ b/src/runtime/gc_test.go @@ -469,3 +469,20 @@ func testAssertVar(x interface{}) error { } return nil } + +func TestAssertE2T2Liveness(t *testing.T) { + *runtime.TestingAssertE2T2GC = true + defer func() { + *runtime.TestingAssertE2T2GC = false + }() + + poisonStack() + testIfaceEqual(io.EOF) +} + +func testIfaceEqual(x interface{}) { + if x == "abc" { + // Prevent inlining + panic("") + } +} diff --git a/src/runtime/iface.go b/src/runtime/iface.go index abd7068ed1..332b7d50ab 100644 --- a/src/runtime/iface.go +++ b/src/runtime/iface.go @@ -229,8 +229,13 @@ func assertE2T(t *_type, e interface{}, r unsafe.Pointer) { } } +var testingAssertE2T2GC bool + // The compiler ensures that r is non-nil. func assertE2T2(t *_type, e interface{}, r unsafe.Pointer) bool { + if testingAssertE2T2GC { + GC() + } ep := (*eface)(unsafe.Pointer(&e)) if ep._type != t { memclr(r, uintptr(t.size))