]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: ignore exceptions from non-Go threads on windows arm/arm64
authorqmuntal <quimmuntal@gmail.com>
Fri, 14 Oct 2022 15:30:45 +0000 (17:30 +0200)
committerGopher Robot <gobot@golang.org>
Wed, 19 Oct 2022 20:21:26 +0000 (20:21 +0000)
If there is no current G while handling an exception it means
the exception was originated in a non-Go thread.

The best we can do is ignore the exception and let it flow
through other vectored and structured error handlers.

I've removed badsignal2 from sigtramp because we can't really know
if the signal is bad or not, it might be handled later in the chain.

Fixes #50877
Updates #56082

Change-Id: Ica159eb843629986d1fb5482f0b59a9c1ed91698
Reviewed-on: https://go-review.googlesource.com/c/go/+/442896
Reviewed-by: Alex Brainman <alex.brainman@gmail.com>
Auto-Submit: Michael Pratt <mpratt@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Michael Pratt <mpratt@google.com>
Run-TryBot: Quim Muntal <quimmuntal@gmail.com>
Reviewed-by: David Chase <drchase@google.com>
src/runtime/signal_windows_test.go
src/runtime/sys_windows_arm.s
src/runtime/sys_windows_arm64.s
src/runtime/testdata/testwinlibthrow/main.go [new file with mode: 0644]
src/runtime/testdata/testwinlibthrow/veh.cpp [new file with mode: 0644]

index 8b32ad89746c3e4464685ec5e891577c2f068c5c..fe74ad56bf99beeff6793636bd342df94e821476 100644 (file)
@@ -17,6 +17,61 @@ import (
        "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")
index 5dc576a260986a543dc0c48ae5dec922dea1b19f..db6d8f1a08741d2be22911baf770c68932c65bec 100644 (file)
@@ -123,8 +123,14 @@ TEXT sigtramp<>(SB),NOSPLIT|NOFRAME,$0
        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)
index b39df4f1241be1309c91fe0e349103fb3eff4c92..4702a4d7d254f742fc58fa12a1464a775e149ab7 100644 (file)
@@ -147,10 +147,15 @@ TEXT sigtramp<>(SB),NOSPLIT|NOFRAME,$0
        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
diff --git a/src/runtime/testdata/testwinlibthrow/main.go b/src/runtime/testdata/testwinlibthrow/main.go
new file mode 100644 (file)
index 0000000..50c483f
--- /dev/null
@@ -0,0 +1,23 @@
+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
diff --git a/src/runtime/testdata/testwinlibthrow/veh.cpp b/src/runtime/testdata/testwinlibthrow/veh.cpp
new file mode 100644 (file)
index 0000000..ed7015a
--- /dev/null
@@ -0,0 +1,53 @@
+//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