From fce0a59fc370634fcd7de8f8691e918cdf122f7d Mon Sep 17 00:00:00 2001
From: Cherry Zhang <cherryyz@google.com>
Date: Thu, 31 Oct 2019 10:32:31 -0400
Subject: [PATCH 4/6] runtime: don't fetch G from signal stack when using cgo

When using cgo, we save G to TLS, and when a signal happens, we
load G from TLS in sigtramp. This should give us a valid G. Don't
try to fetch from the signal stack. In particular, C code may
change the signal stack or call our signal handler directly (e.g.
TSAN), so we are not necessarily running on the original gsignal
stack where we saved G.

Also skip saving G on the signal stack when using cgo.

Updates #35249.

Change-Id: I40749ce6682709bd4ebfdfd9f23bd0f317fc197d
Reviewed-on: https://go-review.googlesource.com/c/go/+/204519
Reviewed-by: Ian Lance Taylor <iant@golang.org>
---
 src/runtime/signal_unix.go    |  8 +++++---
 src/runtime/sys_linux_arm.s   | 30 ++++++++++++++++++++++--------
 src/runtime/sys_linux_arm64.s | 26 ++++++++++++++++++++------
 3 files changed, 47 insertions(+), 17 deletions(-)

diff --git a/src/runtime/signal_unix.go b/src/runtime/signal_unix.go
index 2cf1e3b..721edb5 100644
--- a/src/runtime/signal_unix.go
+++ b/src/runtime/signal_unix.go
@@ -282,9 +282,11 @@ func sigpipe() {
 func sigFetchG(c *sigctxt) *g {
 	switch GOARCH {
 	case "arm", "arm64":
-		if inVDSOPage(c.sigpc()) {
-			// Before making a VDSO call we save the g to the bottom of the
-			// signal stack. Fetch from there.
+		if !iscgo && inVDSOPage(c.sigpc()) {
+			// When using cgo, we save the g on TLS and load it from there
+			// in sigtramp. Just use that.
+			// Otherwise, before making a VDSO call we save the g to the
+			// bottom of the signal stack. Fetch from there.
 			// TODO: in efence mode, stack is sysAlloc'd, so this wouldn't
 			// work.
 			sp := getcallersp()
diff --git a/src/runtime/sys_linux_arm.s b/src/runtime/sys_linux_arm.s
index 26e12a8..a47ac5f 100644
--- a/src/runtime/sys_linux_arm.s
+++ b/src/runtime/sys_linux_arm.s
@@ -250,21 +250,28 @@ noswitch:
 	// during VDSO code we can find the g.
 	// If we don't have a signal stack, we won't receive signal,
 	// so don't bother saving g.
+	// When using cgo, we already saved g on TLS, also don't save
+	// g here.
+	MOVB	runtime·iscgo(SB), R6
+	CMP	$0, R6
+	BNE	nosaveg
 	MOVW	m_gsignal(R5), R6          // g.m.gsignal
 	CMP	$0, R6
-	BEQ	3(PC)
+	BEQ	nosaveg
 	MOVW	(g_stack+stack_lo)(R6), R6 // g.m.gsignal.stack.lo
 	MOVW	g, (R6)
 
 	BL	(R11)
 
-	CMP	$0, R6   // R6 is unchanged by C code
-	BEQ	3(PC)
 	MOVW	$0, R1
-	MOVW	R1, (R6) // clear g slot
+	MOVW	R1, (R6) // clear g slot, R6 is unchanged by C code
 
 	JMP	finish
 
+nosaveg:
+	BL	(R11)
+	JMP	finish
+
 fallback:
 	MOVW	$SYS_clock_gettime, R7
 	SWI	$0
@@ -317,21 +324,28 @@ noswitch:
 	// during VDSO code we can find the g.
 	// If we don't have a signal stack, we won't receive signal,
 	// so don't bother saving g.
+	// When using cgo, we already saved g on TLS, also don't save
+	// g here.
+	MOVB	runtime·iscgo(SB), R6
+	CMP	$0, R6
+	BNE	nosaveg
 	MOVW	m_gsignal(R5), R6          // g.m.gsignal
 	CMP	$0, R6
-	BEQ	3(PC)
+	BEQ	nosaveg
 	MOVW	(g_stack+stack_lo)(R6), R6 // g.m.gsignal.stack.lo
 	MOVW	g, (R6)
 
 	BL	(R11)
 
-	CMP	$0, R6   // R6 is unchanged by C code
-	BEQ	3(PC)
 	MOVW	$0, R1
-	MOVW	R1, (R6) // clear g slot
+	MOVW	R1, (R6) // clear g slot, R6 is unchanged by C code
 
 	JMP	finish
 
+nosaveg:
+	BL	(R11)
+	JMP	finish
+
 fallback:
 	MOVW	$SYS_clock_gettime, R7
 	SWI	$0
diff --git a/src/runtime/sys_linux_arm64.s b/src/runtime/sys_linux_arm64.s
index fd40bf9..94c93ca 100644
--- a/src/runtime/sys_linux_arm64.s
+++ b/src/runtime/sys_linux_arm64.s
@@ -212,18 +212,25 @@ noswitch:
 	// during VDSO code we can find the g.
 	// If we don't have a signal stack, we won't receive signal,
 	// so don't bother saving g.
+	// When using cgo, we already saved g on TLS, also don't save
+	// g here.
+	MOVBU	runtime·iscgo(SB), R22
+	CBNZ	R22, nosaveg
 	MOVD	m_gsignal(R21), R22          // g.m.gsignal
-	CBZ	R22, 3(PC)
+	CBZ	R22, nosaveg
 	MOVD	(g_stack+stack_lo)(R22), R22 // g.m.gsignal.stack.lo
 	MOVD	g, (R22)
 
 	BL	(R2)
 
-	CBZ	R22, 2(PC) // R22 is unchanged by C code
-	MOVD	ZR, (R22)  // clear g slot
+	MOVD	ZR, (R22)  // clear g slot, R22 is unchanged by C code
 
 	B	finish
 
+nosaveg:
+	BL	(R2)
+	B	finish
+
 fallback:
 	MOVD	$SYS_clock_gettime, R8
 	SVC
@@ -269,18 +276,25 @@ noswitch:
 	// during VDSO code we can find the g.
 	// If we don't have a signal stack, we won't receive signal,
 	// so don't bother saving g.
+	// When using cgo, we already saved g on TLS, also don't save
+	// g here.
+	MOVBU	runtime·iscgo(SB), R22
+	CBNZ	R22, nosaveg
 	MOVD	m_gsignal(R21), R22          // g.m.gsignal
-	CBZ	R22, 3(PC)
+	CBZ	R22, nosaveg
 	MOVD	(g_stack+stack_lo)(R22), R22 // g.m.gsignal.stack.lo
 	MOVD	g, (R22)
 
 	BL	(R2)
 
-	CBZ	R22, 2(PC) // R22 is unchanged by C code
-	MOVD	ZR, (R22)  // clear g slot
+	MOVD	ZR, (R22)  // clear g slot, R22 is unchanged by C code
 
 	B	finish
 
+nosaveg:
+	BL	(R2)
+	B	finish
+
 fallback:
 	MOVD	$SYS_clock_gettime, R8
 	SVC
-- 
2.17.1

