--- /dev/null
+// Copyright 2014 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.
+
+// Export guts for testing.
+
+package runtime
+
+var TestingWER = &testingWER
//go:cgo_import_dynamic runtime._NtWaitForSingleObject NtWaitForSingleObject "ntdll.dll"
//go:cgo_import_dynamic runtime._ResumeThread ResumeThread "kernel32.dll"
//go:cgo_import_dynamic runtime._SetConsoleCtrlHandler SetConsoleCtrlHandler "kernel32.dll"
+//go:cgo_import_dynamic runtime._SetErrorMode SetErrorMode "kernel32.dll"
//go:cgo_import_dynamic runtime._SetEvent SetEvent "kernel32.dll"
//go:cgo_import_dynamic runtime._SetProcessPriorityBoost SetProcessPriorityBoost "kernel32.dll"
//go:cgo_import_dynamic runtime._SetThreadPriority SetThreadPriority "kernel32.dll"
_NtWaitForSingleObject,
_ResumeThread,
_SetConsoleCtrlHandler,
+ _SetErrorMode,
_SetEvent,
_SetProcessPriorityBoost,
_SetThreadPriority,
currentThread = ^uintptr(1) // -2 = current thread
)
+const (
+ SEM_FAILCRITICALERRORS = 0x0001
+ SEM_NOGPFAULTERRORBOX = 0x0002
+ SEM_NOALIGNMENTFAULTEXCEPT = 0x0004
+ SEM_NOOPENFILEERRORBOX = 0x8000
+)
+
var (
kernel32Name = []byte("kernel32.dll\x00")
addVectoredContinueHandlerName = []byte("AddVectoredContinueHandler\x00")
kernel32 := stdcall1(_LoadLibraryA, uintptr(unsafe.Pointer(&kernel32Name[0])))
+ // don't display the crash dialog
+ errormode := uint32(stdcall1(_SetErrorMode, SEM_NOGPFAULTERRORBOX))
+ stdcall1(_SetErrorMode, uintptr(errormode)|SEM_FAILCRITICALERRORS|SEM_NOGPFAULTERRORBOX|SEM_NOOPENFILEERRORBOX)
+
externalthreadhandlerp = funcPC(externalthreadhandler)
stdcall2(_AddVectoredExceptionHandler, 1, funcPC(exceptiontramp))
return _EXCEPTION_CONTINUE_EXECUTION
}
+var testingWER bool
+
// lastcontinuehandler is reached, because runtime cannot handle
// current exception. lastcontinuehandler will print crash info and exit.
-func lastcontinuehandler(info *exceptionrecord, r *context, gp *g) uint32 {
+func lastcontinuehandler(info *exceptionrecord, r *context, gp *g) int32 {
+ if testingWER {
+ return _EXCEPTION_CONTINUE_SEARCH
+ }
+
_g_ := getg()
if panicking != 0 { // traceback already printed
return _EXCEPTION_CONTINUE_EXECUTION
}
+var testingWER bool
+
// lastcontinuehandler is reached, because runtime cannot handle
// current exception. lastcontinuehandler will print crash info and exit.
func lastcontinuehandler(info *exceptionrecord, r *context, gp *g) uint32 {
+ if testingWER {
+ return _EXCEPTION_CONTINUE_SEARCH
+ }
+
_g_ := getg()
if panicking != 0 { // traceback already printed
println(z)
}
`
+
+func TestWERDialogue(t *testing.T) {
+ if os.Getenv("TESTING_WER_DIALOGUE") == "1" {
+ defer os.Exit(0)
+
+ *runtime.TestingWER = true
+ const EXCEPTION_NONCONTINUABLE = 1
+ mod := syscall.MustLoadDLL("kernel32.dll")
+ proc := mod.MustFindProc("RaiseException")
+ proc.Call(0xbad, EXCEPTION_NONCONTINUABLE, 0, 0)
+ println("RaiseException should not return")
+ return
+ }
+ cmd := exec.Command(os.Args[0], "-test.run=TestWERDialogue")
+ cmd.Env = []string{"TESTING_WER_DIALOGUE=1"}
+ // Child process should not open WER dialogue, but return immediately instead.
+ cmd.CombinedOutput()
+}