Skip to content

Commit 6fe3ccd

Browse files
qmuntalgopherbot
authored andcommitted
runtime: ignore exceptions from non-Go threads on windows arm/arm64
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 <[email protected]> Auto-Submit: Michael Pratt <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Reviewed-by: Michael Pratt <[email protected]> Run-TryBot: Quim Muntal <[email protected]> Reviewed-by: David Chase <[email protected]>
1 parent 4a164a4 commit 6fe3ccd

File tree

5 files changed

+147
-5
lines changed

5 files changed

+147
-5
lines changed

src/runtime/signal_windows_test.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,61 @@ import (
1717
"testing"
1818
)
1919

20+
func TestVectoredHandlerExceptionInNonGoThread(t *testing.T) {
21+
if *flagQuick {
22+
t.Skip("-quick")
23+
}
24+
testenv.MustHaveGoBuild(t)
25+
testenv.MustHaveCGO(t)
26+
testenv.MustHaveExecPath(t, "g++")
27+
testprog.Lock()
28+
defer testprog.Unlock()
29+
dir := t.TempDir()
30+
31+
// build c program
32+
dll := filepath.Join(dir, "veh.dll")
33+
cmd := exec.Command("g++", "-shared", "-o", dll, "testdata/testwinlibthrow/veh.cpp", "-static", "-lstdc++")
34+
out, err := testenv.CleanCmdEnv(cmd).CombinedOutput()
35+
if err != nil {
36+
t.Fatalf("failed to build c exe: %s\n%s", err, out)
37+
}
38+
39+
// build go exe
40+
exe := filepath.Join(dir, "test.exe")
41+
cmd = exec.Command(testenv.GoToolPath(t), "build", "-o", exe, "testdata/testwinlibthrow/main.go")
42+
out, err = testenv.CleanCmdEnv(cmd).CombinedOutput()
43+
if err != nil {
44+
t.Fatalf("failed to build go library: %s\n%s", err, out)
45+
}
46+
47+
// run test program in same thread
48+
cmd = exec.Command(exe)
49+
out, err = testenv.CleanCmdEnv(cmd).CombinedOutput()
50+
if err == nil {
51+
t.Fatal("error expected")
52+
}
53+
if _, ok := err.(*exec.ExitError); ok && len(out) > 0 {
54+
if !bytes.Contains(out, []byte("Exception 0x2a")) {
55+
t.Fatalf("unexpected failure while running executable: %s\n%s", err, out)
56+
}
57+
} else {
58+
t.Fatalf("unexpected error while running executable: %s\n%s", err, out)
59+
}
60+
// run test program in a new thread
61+
cmd = exec.Command(exe, "thread")
62+
out, err = testenv.CleanCmdEnv(cmd).CombinedOutput()
63+
if err == nil {
64+
t.Fatal("error expected")
65+
}
66+
if err, ok := err.(*exec.ExitError); ok {
67+
if err.ExitCode() != 42 {
68+
t.Fatalf("unexpected failure while running executable: %s\n%s", err, out)
69+
}
70+
} else {
71+
t.Fatalf("unexpected error while running executable: %s\n%s", err, out)
72+
}
73+
}
74+
2075
func TestVectoredHandlerDontCrashOnLibrary(t *testing.T) {
2176
if *flagQuick {
2277
t.Skip("-quick")

src/runtime/sys_windows_arm.s

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,14 @@ TEXT sigtramp<>(SB),NOSPLIT|NOFRAME,$0
123123
MOVW R1, R7 // Save param1
124124

125125
BL runtime·load_g(SB)
126-
CMP $0, g // is there a current g?
127-
BL.EQ runtime·badsignal2(SB)
126+
CMP $0, g // is there a current g?
127+
BNE g_ok
128+
ADD $(8+20), R13 // free locals
129+
MOVM.IA.W (R13), [R3, R4-R11, R14] // pop {r3, r4-r11, lr}
130+
MOVW $0, R0 // continue
131+
BEQ return
132+
133+
g_ok:
128134

129135
// save g and SP in case of stack switch
130136
MOVW R13, 24(R13)

src/runtime/sys_windows_arm64.s

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -147,10 +147,15 @@ TEXT sigtramp<>(SB),NOSPLIT|NOFRAME,$0
147147
MOVD g, R17 // saved R28 (callee-save from Windows, not really g)
148148

149149
BL runtime·load_g(SB) // smashes R0, R27, R28 (g)
150-
CMP $0, g // is there a current g?
151-
BNE 2(PC)
152-
BL runtime·badsignal2(SB)
150+
CMP $0, g // is there a current g?
151+
BNE g_ok
152+
MOVD R7, LR
153+
MOVD R16, R27 // restore R27
154+
MOVD R17, g // restore R28
155+
MOVD $0, R0 // continue
156+
RET
153157

158+
g_ok:
154159
// Do we need to switch to the g0 stack?
155160
MOVD g, R3 // R3 = oldg (for sigtramp_g0)
156161
MOVD g_m(g), R2 // R2 = m
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package main
2+
3+
import (
4+
"os"
5+
"syscall"
6+
)
7+
8+
func main() {
9+
dll := syscall.MustLoadDLL("veh.dll")
10+
RaiseExcept := dll.MustFindProc("RaiseExcept")
11+
RaiseNoExcept := dll.MustFindProc("RaiseNoExcept")
12+
ThreadRaiseExcept := dll.MustFindProc("ThreadRaiseExcept")
13+
ThreadRaiseNoExcept := dll.MustFindProc("ThreadRaiseNoExcept")
14+
15+
thread := len(os.Args) > 1 && os.Args[1] == "thread"
16+
if !thread {
17+
RaiseExcept.Call()
18+
RaiseNoExcept.Call()
19+
} else {
20+
ThreadRaiseExcept.Call()
21+
ThreadRaiseNoExcept.Call()
22+
}
23+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
//go:build ignore
2+
3+
#include <windows.h>
4+
5+
extern "C" __declspec(dllexport)
6+
void RaiseExcept(void)
7+
{
8+
try
9+
{
10+
RaiseException(42, 0, 0, 0);
11+
}
12+
catch (...)
13+
{
14+
}
15+
}
16+
17+
extern "C" __declspec(dllexport)
18+
void RaiseNoExcept(void)
19+
{
20+
RaiseException(42, 0, 0, 0);
21+
}
22+
23+
static DWORD WINAPI ThreadRaiser(void* Context)
24+
{
25+
if (Context)
26+
RaiseExcept();
27+
else
28+
RaiseNoExcept();
29+
return 0;
30+
}
31+
32+
static void ThreadRaiseXxx(int except)
33+
{
34+
static int dummy;
35+
HANDLE thread = CreateThread(0, 0, ThreadRaiser, except ? &dummy : 0, 0, 0);
36+
if (0 != thread)
37+
{
38+
WaitForSingleObject(thread, INFINITE);
39+
CloseHandle(thread);
40+
}
41+
}
42+
43+
extern "C" __declspec(dllexport)
44+
void ThreadRaiseExcept(void)
45+
{
46+
ThreadRaiseXxx(1);
47+
}
48+
49+
extern "C" __declspec(dllexport)
50+
void ThreadRaiseNoExcept(void)
51+
{
52+
ThreadRaiseXxx(0);
53+
}

0 commit comments

Comments
 (0)