"testing"
)
+func TestVectoredHandlerExceptionInNonGoThread(t *testing.T) {
+ if *flagQuick {
+ t.Skip("-quick")
+ }
+ testenv.MustHaveGoBuild(t)
+ testenv.MustHaveCGO(t)
+ testenv.MustHaveExecPath(t, "g++")
+ testprog.Lock()
+ defer testprog.Unlock()
+ dir := t.TempDir()
+
+ // build c program
+ dll := filepath.Join(dir, "veh.dll")
+ cmd := exec.Command("g++", "-shared", "-o", dll, "testdata/testwinlibthrow/veh.cpp", "-static", "-lstdc++")
+ out, err := testenv.CleanCmdEnv(cmd).CombinedOutput()
+ if err != nil {
+ t.Fatalf("failed to build c exe: %s\n%s", err, out)
+ }
+
+ // build go exe
+ exe := filepath.Join(dir, "test.exe")
+ cmd = exec.Command(testenv.GoToolPath(t), "build", "-o", exe, "testdata/testwinlibthrow/main.go")
+ out, err = testenv.CleanCmdEnv(cmd).CombinedOutput()
+ if err != nil {
+ t.Fatalf("failed to build go library: %s\n%s", err, out)
+ }
+
+ // run test program in same thread
+ cmd = exec.Command(exe)
+ out, err = testenv.CleanCmdEnv(cmd).CombinedOutput()
+ if err == nil {
+ t.Fatal("error expected")
+ }
+ if _, ok := err.(*exec.ExitError); ok && len(out) > 0 {
+ if !bytes.Contains(out, []byte("Exception 0x2a")) {
+ t.Fatalf("unexpected failure while running executable: %s\n%s", err, out)
+ }
+ } else {
+ t.Fatalf("unexpected error while running executable: %s\n%s", err, out)
+ }
+ // run test program in a new thread
+ cmd = exec.Command(exe, "thread")
+ out, err = testenv.CleanCmdEnv(cmd).CombinedOutput()
+ if err == nil {
+ t.Fatal("error expected")
+ }
+ if err, ok := err.(*exec.ExitError); ok {
+ if err.ExitCode() != 42 {
+ t.Fatalf("unexpected failure while running executable: %s\n%s", err, out)
+ }
+ } else {
+ t.Fatalf("unexpected error while running executable: %s\n%s", err, out)
+ }
+}
+
func TestVectoredHandlerDontCrashOnLibrary(t *testing.T) {
if *flagQuick {
t.Skip("-quick")
MOVW R1, R7 // Save param1
BL runtime·load_g(SB)
- CMP $0, g // is there a current g?
- BL.EQ runtime·badsignal2(SB)
+ CMP $0, g // is there a current g?
+ BNE g_ok
+ ADD $(8+20), R13 // free locals
+ MOVM.IA.W (R13), [R3, R4-R11, R14] // pop {r3, r4-r11, lr}
+ MOVW $0, R0 // continue
+ BEQ return
+
+g_ok:
// save g and SP in case of stack switch
MOVW R13, 24(R13)
MOVD g, R17 // saved R28 (callee-save from Windows, not really g)
BL runtime·load_g(SB) // smashes R0, R27, R28 (g)
- CMP $0, g // is there a current g?
- BNE 2(PC)
- BL runtime·badsignal2(SB)
+ CMP $0, g // is there a current g?
+ BNE g_ok
+ MOVD R7, LR
+ MOVD R16, R27 // restore R27
+ MOVD R17, g // restore R28
+ MOVD $0, R0 // continue
+ RET
+g_ok:
// Do we need to switch to the g0 stack?
MOVD g, R3 // R3 = oldg (for sigtramp_g0)
MOVD g_m(g), R2 // R2 = m
--- /dev/null
+package main\r
+\r
+import (\r
+ "os"\r
+ "syscall"\r
+)\r
+\r
+func main() {\r
+ dll := syscall.MustLoadDLL("veh.dll")\r
+ RaiseExcept := dll.MustFindProc("RaiseExcept")\r
+ RaiseNoExcept := dll.MustFindProc("RaiseNoExcept")\r
+ ThreadRaiseExcept := dll.MustFindProc("ThreadRaiseExcept")\r
+ ThreadRaiseNoExcept := dll.MustFindProc("ThreadRaiseNoExcept")\r
+\r
+ thread := len(os.Args) > 1 && os.Args[1] == "thread"\r
+ if !thread {\r
+ RaiseExcept.Call()\r
+ RaiseNoExcept.Call()\r
+ } else {\r
+ ThreadRaiseExcept.Call()\r
+ ThreadRaiseNoExcept.Call()\r
+ }\r
+}\r
--- /dev/null
+//go:build ignore\r
+\r
+#include <windows.h>\r
+\r
+extern "C" __declspec(dllexport)\r
+void RaiseExcept(void)\r
+{\r
+ try\r
+ {\r
+ RaiseException(42, 0, 0, 0);\r
+ }\r
+ catch (...)\r
+ {\r
+ }\r
+}\r
+\r
+extern "C" __declspec(dllexport)\r
+void RaiseNoExcept(void)\r
+{\r
+ RaiseException(42, 0, 0, 0);\r
+}\r
+\r
+static DWORD WINAPI ThreadRaiser(void* Context)\r
+{\r
+ if (Context)\r
+ RaiseExcept();\r
+ else\r
+ RaiseNoExcept();\r
+ return 0;\r
+}\r
+\r
+static void ThreadRaiseXxx(int except)\r
+{\r
+ static int dummy;\r
+ HANDLE thread = CreateThread(0, 0, ThreadRaiser, except ? &dummy : 0, 0, 0);\r
+ if (0 != thread)\r
+ {\r
+ WaitForSingleObject(thread, INFINITE);\r
+ CloseHandle(thread);\r
+ }\r
+}\r
+\r
+extern "C" __declspec(dllexport)\r
+void ThreadRaiseExcept(void)\r
+{\r
+ ThreadRaiseXxx(1);\r
+}\r
+\r
+extern "C" __declspec(dllexport)\r
+void ThreadRaiseNoExcept(void)\r
+{\r
+ ThreadRaiseXxx(0);\r
+}\r