1
0
mirror of https://github.com/golang/go synced 2024-11-18 17:14:45 -07:00

go/ssa/interp: delete SSA bodies from standalone functions in "reflect"

...like we do for "runtime" functions, so that they fail informatively
if executed.  They all need intrinsics, but only some are yet defined.

Also:
- added test for issue 9462
- "BUG" in test output is now a failure in all tests (not just $GOROOT tests)
- added intrinsic for reflect.SliceOf
- show dynamic type of panic value

Fixes issue 9462

Change-Id: I3a504c7faeed81e922fedc7dd59222717f3a7e95
Reviewed-on: https://go-review.googlesource.com/2145
Reviewed-by: Robert Griesemer <gri@golang.org>
This commit is contained in:
Alan Donovan 2014-12-29 11:44:01 -05:00
parent ca3901c3d8
commit 4b1d99f7f3
5 changed files with 43 additions and 28 deletions

View File

@ -80,6 +80,7 @@ func init() {
"math.Min": ext۰math۰Min,
"os.runtime_args": ext۰os۰runtime_args,
"reflect.New": ext۰reflect۰New,
"reflect.SliceOf": ext۰reflect۰SliceOf,
"reflect.TypeOf": ext۰reflect۰TypeOf,
"reflect.ValueOf": ext۰reflect۰ValueOf,
"reflect.init": ext۰reflect۰Init,

View File

@ -631,6 +631,20 @@ func init() {
environ = append(environ, "GOARCH="+runtime.GOARCH)
}
// deleteBodies delete the bodies of all standalone functions except the
// specified ones. A missing intrinsic leads to a clear runtime error.
func deleteBodies(pkg *ssa.Package, except ...string) {
keep := make(map[string]bool)
for _, e := range except {
keep[e] = true
}
for _, mem := range pkg.Members {
if fn, ok := mem.(*ssa.Function); ok && !keep[fn.Name()] {
fn.Blocks = nil
}
}
}
// Interpret interprets the Go program whose main package is mainpkg.
// mode specifies various interpreter options. filename and args are
// the initial values of os.Args for the target program. sizes is the
@ -676,22 +690,13 @@ func Interpret(mainpkg *ssa.Package, mode Mode, sizes types.Sizes, filename stri
case "syscall":
setGlobal(i, pkg, "envs", environ)
case "reflect":
deleteBodies(pkg, "DeepEqual", "deepValueEqual")
case "runtime":
sz := sizes.Sizeof(pkg.Object.Scope().Lookup("MemStats").Type())
setGlobal(i, pkg, "sizeof_C_MStats", uintptr(sz))
// Delete the bodies of almost all "runtime" functions since they're magic.
// A missing intrinsic leads to a very clear error.
for _, mem := range pkg.Members {
if fn, ok := mem.(*ssa.Function); ok {
switch fn.Name() {
case "GOROOT", "gogetenv":
// keep
default:
fn.Blocks = nil
}
}
}
deleteBodies(pkg, "GOROOT", "gogetenv")
}
}
@ -712,7 +717,7 @@ func Interpret(mainpkg *ssa.Package, mode Mode, sizes types.Sizes, filename stri
case string:
fmt.Fprintln(os.Stderr, "panic:", p)
default:
fmt.Fprintf(os.Stderr, "panic: unexpected type: %T\n", p)
fmt.Fprintf(os.Stderr, "panic: unexpected type: %T: %v\n", p, p)
}
// TODO(adonovan): dump panicking interpreter goroutine?

View File

@ -146,6 +146,7 @@ var testdataTests = []string{
"mrvchain.go",
"range.go",
"recover.go",
"reflect.go",
"static.go",
"callstack.go",
}
@ -276,11 +277,13 @@ func printFailures(failures []string) {
}
}
// The "normal" success predicate.
func exitsZero(exitcode int, _ string) error {
func success(exitcode int, output string) error {
if exitcode != 0 {
return fmt.Errorf("exit code was %d", exitcode)
}
if strings.Contains(output, "BUG") {
return fmt.Errorf("exited zero but output contained 'BUG'")
}
return nil
}
@ -288,7 +291,7 @@ func exitsZero(exitcode int, _ string) error {
func TestTestdataFiles(t *testing.T) {
var failures []string
for _, input := range testdataTests {
if !run(t, "testdata"+slash, input, exitsZero) {
if !run(t, "testdata"+slash, input, success) {
failures = append(failures, input)
}
}
@ -303,16 +306,6 @@ func TestGorootTest(t *testing.T) {
var failures []string
// $GOROOT/tests are also considered a failure if they print "BUG".
success := func(exitcode int, output string) error {
if exitcode != 0 {
return fmt.Errorf("exit code was %d", exitcode)
}
if strings.Contains(output, "BUG") {
return fmt.Errorf("exited zero but output contained 'BUG'")
}
return nil
}
for _, input := range gorootTestTests {
if !run(t, filepath.Join(build.Default.GOROOT, "test")+slash, input, success) {
failures = append(failures, input)

View File

@ -150,8 +150,13 @@ func ext۰reflect۰New(fr *frame, args []value) value {
return makeReflectValue(types.NewPointer(t), &alloc)
}
func ext۰reflect۰SliceOf(fr *frame, args []value) value {
// Signature: func (t reflect.rtype) Type
return makeReflectType(rtype{types.NewSlice(args[0].(iface).v.(rtype).t)})
}
func ext۰reflect۰TypeOf(fr *frame, args []value) value {
// Signature: func (t reflect.rtype) string
// Signature: func (t reflect.rtype) Type
return makeReflectType(rtype{args[0].(iface).t})
}

11
go/ssa/interp/testdata/reflect.go vendored Normal file
View File

@ -0,0 +1,11 @@
package main
import "reflect"
func main() {
// Regression test for issue 9462.
got := reflect.SliceOf(reflect.TypeOf(byte(0))).String()
if got != "[]uint8" && got != "[]byte" { // result varies by toolchain
println("BUG: " + got)
}
}