diff options
author | Cherry Zhang <cherryyz@google.com> | 2019-10-23 11:42:23 -0400 |
---|---|---|
committer | Cherry Zhang <cherryyz@google.com> | 2019-10-23 22:59:54 +0000 |
commit | 758eb020f72a70e3e42814492daac8719a3be538 (patch) | |
tree | 1bbbdad699accc81f2a36c719f2bfc439a85b042 /src/runtime/signal_unix.go | |
parent | 20bba866d3aaeba728c78ff24c940b98441c791b (diff) | |
download | go-758eb020f72a70e3e42814492daac8719a3be538.tar.gz go-758eb020f72a70e3e42814492daac8719a3be538.zip |
runtime: save/fetch g register during VDSO on ARM and ARM64
On ARM and ARM64, during a VDSO call, the g register may be
temporarily clobbered by the VDSO code. If a signal is received
during the execution of VDSO code, we may not find a valid g
reading the g register. In CL 192937, we conservatively assume
g is nil. But this approach has a problem: we cannot handle
the signal in this case. Further, if the signal is not a
profiling signal, we'll call badsignal, which calls needm, which
wants to get an extra m, but we don't have one in a non-cgo
binary, which cuases the program to hang.
This is even more of a problem with async preemption, where we
will receive more signals than before. I ran into this problem
while working on async preemption support on ARM64.
In this CL, before making a VDSO call, we save the g on the
gsignal stack. When we receive a signal, we will be running on
the gsignal stack, so we can fetch the g from there and move on.
We probably want to do the same for PPC64. Currently we rely on
that the VDSO code doesn't actually clobber the g register, but
this is not guaranteed and we don't have control with.
Idea from discussion with Dan Cross and Austin.
Should fix #34391.
Change-Id: Idbefc5e4c2f4373192c2be797be0140ae08b26e3
Reviewed-on: https://go-review.googlesource.com/c/go/+/202759
Run-TryBot: Cherry Zhang <cherryyz@google.com>
Reviewed-by: Austin Clements <austin@google.com>
Diffstat (limited to 'src/runtime/signal_unix.go')
-rw-r--r-- | src/runtime/signal_unix.go | 10 |
1 files changed, 10 insertions, 0 deletions
diff --git a/src/runtime/signal_unix.go b/src/runtime/signal_unix.go index d5a04b6d48..cea65282e0 100644 --- a/src/runtime/signal_unix.go +++ b/src/runtime/signal_unix.go @@ -299,6 +299,16 @@ 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. + // TODO: in efence mode, stack is sysAlloc'd, so this wouldn't + // work. + sp := getcallersp() + s := spanOf(sp) + if s != nil && s.state == mSpanManual && s.base() < sp && sp < s.limit { + gp := *(**g)(unsafe.Pointer(s.base())) + return gp + } return nil } } |