-
Notifications
You must be signed in to change notification settings - Fork 17.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
runtime: adjust gsignal stack to current signal stack
If non-Go code calls sigaltstack before a signal is received, use sigaltstack to determine the current signal stack and set the gsignal stack to use it. This makes the Go runtime more robust in the face of non-Go code. We still can't handle a disabled signal stack or a signal triggered with SA_ONSTACK clear, but we now give clear errors for those cases. Fixes #7227. Update #9896. Change-Id: Icb1607e01fd6461019b6d77d940e59b3aed4d258 Reviewed-on: https://go-review.googlesource.com/18102 Run-TryBot: Ian Lance Taylor <iant@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Mikio Hara <mikioh.mikioh@gmail.com>
- Loading branch information
1 parent
e4dcf5c
commit f7e51c1
Showing
23 changed files
with
419 additions
and
327 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
// Copyright 2015 The Go Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style | ||
// license that can be found in the LICENSE file. | ||
|
||
// +build !windows | ||
|
||
package cgotest | ||
|
||
import "testing" | ||
|
||
func TestSigaltstack(t *testing.T) { testSigaltstack(t) } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
// Copyright 2015 The Go Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style | ||
// license that can be found in the LICENSE file. | ||
|
||
// +build !windows | ||
|
||
// Test that the Go runtime still works if C code changes the signal stack. | ||
|
||
package cgotest | ||
|
||
/* | ||
#include <signal.h> | ||
#include <stdio.h> | ||
#include <stdlib.h> | ||
#include <string.h> | ||
static stack_t oss; | ||
static char signalStack[SIGSTKSZ]; | ||
static void changeSignalStack() { | ||
stack_t ss; | ||
memset(&ss, 0, sizeof ss); | ||
ss.ss_sp = signalStack; | ||
ss.ss_flags = 0; | ||
ss.ss_size = SIGSTKSZ; | ||
if (sigaltstack(&ss, &oss) < 0) { | ||
perror("sigaltstack"); | ||
abort(); | ||
} | ||
} | ||
static void restoreSignalStack() { | ||
#if defined(__x86_64__) && defined(__APPLE__) | ||
// The Darwin C library enforces a minimum that the kernel does not. | ||
// This is OK since we allocated this much space in mpreinit, | ||
// it was just removed from the buffer by stackalloc. | ||
oss.ss_size = MINSIGSTKSZ; | ||
#endif | ||
if (sigaltstack(&oss, NULL) < 0) { | ||
perror("sigaltstack restore"); | ||
abort(); | ||
} | ||
} | ||
static int zero() { | ||
return 0; | ||
} | ||
*/ | ||
import "C" | ||
|
||
import ( | ||
"runtime" | ||
"testing" | ||
) | ||
|
||
func testSigaltstack(t *testing.T) { | ||
switch { | ||
case runtime.GOOS == "solaris", runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64"): | ||
t.Skipf("switching signal stack not implemented on %s/s", runtime.GOOS, runtime.GOARCH) | ||
} | ||
|
||
C.changeSignalStack() | ||
defer C.restoreSignalStack() | ||
defer func() { | ||
if recover() == nil { | ||
t.Error("did not see expected panic") | ||
} | ||
}() | ||
v := 1 / int(C.zero()) | ||
t.Errorf("unexpected success of division by zero == %d", v) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
// Copyright 2009 The Go Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style | ||
// license that can be found in the LICENSE file. | ||
|
||
// +build dragonfly linux netbsd | ||
|
||
package runtime | ||
|
||
import "unsafe" | ||
|
||
// Continuation of the (assembly) sigtramp() logic. | ||
//go:nosplit | ||
func sigtrampgo(sig uint32, info *siginfo, ctx unsafe.Pointer) { | ||
if sigfwdgo(sig, info, ctx) { | ||
return | ||
} | ||
g := getg() | ||
if g == nil { | ||
badsignal(uintptr(sig)) | ||
return | ||
} | ||
|
||
// If some non-Go code called sigaltstack, adjust. | ||
sp := uintptr(unsafe.Pointer(&sig)) | ||
if sp < g.m.gsignal.stack.lo || sp >= g.m.gsignal.stack.hi { | ||
var st sigaltstackt | ||
sigaltstack(nil, &st) | ||
if st.ss_flags&_SS_DISABLE != 0 { | ||
setg(nil) | ||
cgocallback(unsafe.Pointer(funcPC(noSignalStack)), noescape(unsafe.Pointer(&sig)), unsafe.Sizeof(sig)) | ||
} | ||
stsp := uintptr(unsafe.Pointer(st.ss_sp)) | ||
if sp < stsp || sp >= stsp+st.ss_size { | ||
setg(nil) | ||
cgocallback(unsafe.Pointer(funcPC(sigNotOnStack)), noescape(unsafe.Pointer(&sig)), unsafe.Sizeof(sig)) | ||
} | ||
g.m.gsignal.stack.lo = stsp | ||
g.m.gsignal.stack.hi = stsp + st.ss_size | ||
g.m.gsignal.stackguard0 = stsp + _StackGuard | ||
g.m.gsignal.stackguard1 = stsp + _StackGuard | ||
g.m.gsignal.stackAlloc = st.ss_size | ||
g.m.gsignal.stktopsp = getcallersp(unsafe.Pointer(&sig)) | ||
} | ||
|
||
setg(g.m.gsignal) | ||
sighandler(sig, info, ctx, g) | ||
setg(g) | ||
} |
Oops, something went wrong.