]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: round return value address in runtime.equal
authorShenghou Ma <minux.ma@gmail.com>
Wed, 1 Aug 2012 03:02:46 +0000 (23:02 -0400)
committerShenghou Ma <minux.ma@gmail.com>
Wed, 1 Aug 2012 03:02:46 +0000 (23:02 -0400)
     Fixes #3866.

R=rsc, r, nigeltao
CC=golang-dev
https://golang.org/cl/6452046

src/pkg/runtime/alg.c
test/fixedbugs/bug449.go [new file with mode: 0644]

index 36973eba332ddff7d7959e95f2d55f95abc861e1..bc848da38cd109345f2cf92120ec496e2f664ec2 100644 (file)
@@ -469,10 +469,11 @@ void
 runtime·equal(Type *t, ...)
 {
        byte *x, *y;
-       bool *ret;
+       uintptr ret;
        
        x = (byte*)(&t+1);
-       y = x + t->size;
-       ret = (bool*)(y + t->size);
-       t->alg->equal(ret, t->size, x, y);
+       y = x + ROUND(t->size, t->align);
+       ret = (uintptr)(y + t->size);
+       ret = ROUND(ret, Structrnd);
+       t->alg->equal((bool*)ret, t->size, x, y);
 }
diff --git a/test/fixedbugs/bug449.go b/test/fixedbugs/bug449.go
new file mode 100644 (file)
index 0000000..a9650f4
--- /dev/null
@@ -0,0 +1,69 @@
+// runoutput
+
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 3866
+// runtime.equal failed to take padding between arguments and
+// return values into account, so in certain cases gc-generated
+// code will read a random bool from the stack as the result of
+// the comparison.
+// This program generates a lot of equality tests and hopes to
+// catch this.
+// NOTE: this program assumes comparing instance of T and T's
+// underlying []byte will make gc emit calls to runtime.equal,
+// and if gc optimizes this case, then the test will no longer
+// be correct (in the sense that it no longer tests runtime.equal).
+
+package main
+
+import (
+       "bytes"
+       "fmt"
+       "strconv"
+       "strings"
+)
+
+const ntest = 1024
+
+func main() {
+       var decls, calls bytes.Buffer
+
+       for i := 1; i <= ntest; i++ {
+               s := strconv.Itoa(i)
+               decls.WriteString(strings.Replace(decl, "$", s, -1))
+               calls.WriteString(strings.Replace("call(test$)\n\t", "$", s, -1))
+       }
+
+       program = strings.Replace(program, "$DECLS", decls.String(), 1)
+       program = strings.Replace(program, "$CALLS", calls.String(), 1)
+       fmt.Print(program)
+}
+
+var program = `package main
+
+var count int
+
+func call(f func() bool) {
+       if f() {
+               count++
+       }
+}
+
+$DECLS
+
+func main() {
+       $CALLS
+       if count != 0 {
+               println("failed", count, "case(s)")
+       }
+}
+`
+
+const decl = `
+type T$ [$]uint8
+func test$() bool {
+       v := T${1}
+       return v == [$]uint8{2} || v != [$]uint8{1}
+}`