go.tools/ssa: ensure address-deriving operations panic on nil inputs.

&x.f, &x[0], x[i:j], &*x all must panic if x==nil.

The first three are already addressed by the semantics of
FieldAddr, IndexAddr, Slice; updated docs to reflect this.
The final case requires generation of an additional dynamic check.

See golang.org/s/go12nil for details.

Tested on $GOROOT/test/nilptr2.go (with patch from CL 13108043)

Also: remove a TODO where a no-op will do.

R=gri, crawshaw
CC=golang-dev, rsc
https://golang.org/cl/13064044
This commit is contained in:
Alan Donovan 2013-08-19 17:51:33 -04:00
parent 7072253af5
commit 5cbf2abd36
3 changed files with 9 additions and 4 deletions

View File

@ -438,8 +438,6 @@ func (b *builder) addr(fn *Function, e ast.Expr, escaping bool) lvalue {
return &address{addr: fn.emit(v), expr: e}
case *ast.StarExpr:
// TODO(adonovan): fix: implement nil-check if e.X
// evaluates to nil, per http://golang.org/s/go12nil.
return &address{addr: b.expr(fn, e.X), starPos: e.Star, expr: e}
}
@ -562,7 +560,14 @@ func (b *builder) expr(fn *Function, e ast.Expr) (result Value) {
case *ast.UnaryExpr:
switch e.Op {
case token.AND: // &X --- potentially escaping.
return b.addr(fn, e.X, true).address(fn)
addr := b.addr(fn, e.X, true)
if _, ok := unparen(e.X).(*ast.StarExpr); ok {
// &*p must panic if p is nil (http://golang.org/s/go12nil).
// For simplicity, we'll just (suboptimally) rely
// on the side effects of a load.
addr.load(fn)
}
return addr.address(fn)
case token.ADD:
return b.expr(fn, e.X)
case token.NOT, token.ARROW, token.SUB, token.XOR: // ! <- - ^

View File

@ -152,7 +152,6 @@ func ext۰runtime۰getgoroot(fn *ssa.Function, args []value) value {
}
func ext۰sync۰runtime_Syncsemcheck(fn *ssa.Function, args []value) value {
// TODO(adonovan): do equivalent of calling runtime_Syncsemcheck(size uintptr) here
return nil
}

View File

@ -59,6 +59,7 @@ var gorootTestTests = []string{
"gc.go",
"simassign.go",
"iota.go",
"nilptr2.go",
"goprint.go", // doesn't actually assert anything
"utf.go",
"method.go",