// We expect to crash, so exit 0 to indicate failure.
os.Exit(0)
}
+ if os.Getenv("GO_TEST_RUNTIME_NPE_READMEMSTATS") == "1" {
+ runtime.ReadMemStats(nil)
+ os.Exit(0)
+ }
+ if os.Getenv("GO_TEST_RUNTIME_NPE_FUNCMETHOD") == "1" {
+ var f *runtime.Func
+ _ = f.Entry()
+ os.Exit(0)
+ }
+
}
func TestRuntimePanic(t *testing.T) {
}
}
+func TestTracebackRuntimeFunction(t *testing.T) {
+ testenv.MustHaveExec(t)
+ cmd := testenv.CleanCmdEnv(exec.Command(os.Args[0], "-test.run=TestTracebackRuntimeFunction"))
+ cmd.Env = append(cmd.Env, "GO_TEST_RUNTIME_NPE_READMEMSTATS=1")
+ out, err := cmd.CombinedOutput()
+ t.Logf("%s", out)
+ if err == nil {
+ t.Error("child process did not fail")
+ } else if want := "runtime.ReadMemStats"; !bytes.Contains(out, []byte(want)) {
+ t.Errorf("output did not contain expected string %q", want)
+ }
+}
+
+func TestTracebackRuntimeMethod(t *testing.T) {
+ testenv.MustHaveExec(t)
+ cmd := testenv.CleanCmdEnv(exec.Command(os.Args[0], "-test.run=TestTracebackRuntimeMethod"))
+ cmd.Env = append(cmd.Env, "GO_TEST_RUNTIME_NPE_FUNCMETHOD=1")
+ out, err := cmd.CombinedOutput()
+ t.Logf("%s", out)
+ if err == nil {
+ t.Error("child process did not fail")
+ } else if want := "runtime.(*Func).Entry"; !bytes.Contains(out, []byte(want)) {
+ t.Errorf("output did not contain expected string %q", want)
+ }
+}
+
// Test that g0 stack overflows are handled gracefully.
func TestG0StackOverflow(t *testing.T) {
testenv.MustHaveExec(t)
// isExportedRuntime reports whether name is an exported runtime function.
// It is only for runtime functions, so ASCII A-Z is fine.
-// TODO: this handles exported functions but not exported methods.
func isExportedRuntime(name string) bool {
- const n = len("runtime.")
- return len(name) > n && name[:n] == "runtime." && 'A' <= name[n] && name[n] <= 'Z'
+ // Check and remove package qualifier.
+ n := len("runtime.")
+ if len(name) <= n || name[:n] != "runtime." {
+ return false
+ }
+ name = name[n:]
+ rcvr := ""
+
+ // Extract receiver type, if any.
+ // For example, runtime.(*Func).Entry
+ i := len(name) - 1
+ for i >= 0 && name[i] != '.' {
+ i--
+ }
+ if i >= 0 {
+ rcvr = name[:i]
+ name = name[i+1:]
+ // Remove parentheses and star for pointer receivers.
+ if len(rcvr) >= 3 && rcvr[0] == '(' && rcvr[1] == '*' && rcvr[len(rcvr)-1] == ')' {
+ rcvr = rcvr[2 : len(rcvr)-1]
+ }
+ }
+
+ // Exported functions and exported methods on exported types.
+ return len(name) > 0 && 'A' <= name[0] && name[0] <= 'Z' && (len(rcvr) == 0 || 'A' <= rcvr[0] && rcvr[0] <= 'Z')
}
// elideWrapperCalling reports whether a wrapper function that called