cmd/gc: fix use of nil interface, slice

Fixes #3670.

R=ken2
CC=golang-dev
https://golang.org/cl/6542058
This commit is contained in:
Russ Cox 2012-09-22 20:42:11 -04:00
parent b51ad9cf45
commit 05ac300830
6 changed files with 74 additions and 1 deletions

View file

@ -554,6 +554,21 @@ agen(Node *n, Node *res)
while(n->op == OCONVNOP)
n = n->left;
if(isconst(n, CTNIL) && n->type->width > widthptr) {
// Use of a nil interface or nil slice.
// Create a temporary we can take the address of and read.
// The generated code is just going to panic, so it need not
// be terribly efficient. See issue 3670.
tempname(&n1, n->type);
clearfat(&n1);
regalloc(&n2, types[tptr], res);
gins(ALEAQ, &n1, &n2);
gmove(&n2, res);
regfree(&n2);
goto ret;
}
if(n->addable) {
memset(&n1, 0, sizeof n1);
n1.op = OADDR;

View file

@ -518,6 +518,20 @@ agen(Node *n, Node *res)
while(n->op == OCONVNOP)
n = n->left;
if(isconst(n, CTNIL) && n->type->width > widthptr) {
// Use of a nil interface or nil slice.
// Create a temporary we can take the address of and read.
// The generated code is just going to panic, so it need not
// be terribly efficient. See issue 3670.
tempname(&n1, n->type);
clearfat(&n1);
regalloc(&n2, types[tptr], res);
gins(ALEAQ, &n1, &n2);
gmove(&n2, res);
regfree(&n2);
goto ret;
}
if(n->addable) {
regalloc(&n1, types[tptr], res);
gins(ALEAQ, n, &n1);

View file

@ -990,6 +990,13 @@ gins(int as, Node *f, Node *t)
case AMOVSD:
if(f != N && t != N && samaddr(f, t))
return nil;
break;
case ALEAQ:
if(f != N && isconst(f, CTNIL)) {
fatal("gins LEAQ nil %T", f->type);
}
break;
}
memset(&af, 0, sizeof af);

View file

@ -509,6 +509,20 @@ agen(Node *n, Node *res)
while(n->op == OCONVNOP)
n = n->left;
if(isconst(n, CTNIL) && n->type->width > widthptr) {
// Use of a nil interface or nil slice.
// Create a temporary we can take the address of and read.
// The generated code is just going to panic, so it need not
// be terribly efficient. See issue 3670.
tempname(&n1, n->type);
clearfat(&n1);
regalloc(&n2, types[tptr], res);
gins(ALEAL, &n1, &n2);
gmove(&n2, res);
regfree(&n2);
return;
}
// addressable var is easy
if(n->addable) {
if(n->op == OREGISTER)

View file

@ -1732,6 +1732,12 @@ gins(int as, Node *f, Node *t)
case AMOVL:
if(f != N && t != N && samaddr(f, t))
return nil;
break;
case ALEAL:
if(f != N && isconst(f, CTNIL))
fatal("gins LEAQ nil %T", f->type);
break;
}
memset(&af, 0, sizeof af);

View file

@ -6,6 +6,7 @@
// The no-op conversion here used to confuse the compiler
// into doing a load-effective-address of nil.
// See issue 3670.
package main
@ -13,7 +14,23 @@ import "reflect"
type T interface {}
var x bool
func main() {
reflect.TypeOf(nil)
reflect.TypeOf(T(nil)) // used to fail
reflect.TypeOf(T(nil)) // used to miscompile
shouldPanic()
}
func f() byte {
return []byte(nil)[0] // used to miscompile
}
func shouldPanic() {
defer func() {
if recover() == nil {
panic("not panicking")
}
}()
f()
}