Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

runtime: signal handling: cgoSigtramp fails to save C callee-save registers. #18328

Closed
bcmills opened this issue Dec 15, 2016 · 4 comments
Closed

Comments

@bcmills
Copy link
Contributor

bcmills commented Dec 15, 2016

In programs using cgo, runtime.setsig registers runtime.cgoSigtramp as the handler for signals to the runtime. cgoSigtramp calls sigtramp, which calls sigtrampgo, which uses the Go calling convention. The Go convention treats all registers except the stack pointer and frame pointer as caller-save (#16922).

In debugging #17641, I noticed that cgoSigtramp does not save the C callee-save registers before invoking those Go functions. If the call to the Go handler is forwarded through other C handlers (as in the case of TSAN interceptors; see #18255), that potentially results in corruption of the register contents and undefined behavior when control returns to the C caller.

I am attempting to write a reproducible test-case and will post it here as an update.

@bcmills
Copy link
Contributor Author

bcmills commented Dec 15, 2016

The repro case is a minor variation on the test-case added in change 34239, obtained by making a local variable live across the invocation of the deferred handler:

$ diff -u $GOROOT/misc/cgo/testsanitizers/tsan9.go ./issue18328.go
--- /home/bcmills/src/go/misc/cgo/testsanitizers/tsan9.go      2016-12-15 11:54:46.895601246 -0800
+++ ./issue18328.go     2016-12-15 12:40:58.691484523 -0800
@@ -19,10 +19,14 @@
        size_t n;
        struct timeval tvstart, tvnow;
        int diff;
+       void *prev = NULL, *cur;

        gettimeofday(&tvstart, NULL);
        for (n = 0; n < 1<<20; n++) {
-               free(malloc(n));
+               cur = malloc(n);
+               free(prev);
+               prev = cur;
+
                gettimeofday(&tvnow, NULL);
                diff = (tvnow.tv_sec - tvstart.tv_sec) * 1000 * 1000 + (tvnow.tv_usec - tvstart.tv_usec);

@@ -32,6 +36,8 @@
                        break;
                }
        }
+
+       free(prev);
 }
 */
 import "C"
$ go version
go version devel +94e0f06 Thu Dec 15 18:17:32 2016 +0000 linux/amd64
$ $(go env CC) --version
clang version 3.8.0-2ubuntu3~trusty4 (tags/RELEASE_380/final)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
$ go build issue18328 && ./issue18328
Segmentation fault (core dumped)

@bcmills
Copy link
Contributor Author

bcmills commented Dec 15, 2016

@ianlancetaylor: I'm guessing one of us should fix this. I'm happy to send a patch unless you want to do it yourself.

@gopherbot
Copy link

CL https://golang.org/cl/34501 mentions this issue.

@gopherbot
Copy link

CL https://golang.org/cl/35068 mentions this issue.

gopherbot pushed a commit that referenced this issue Jan 12, 2017
Use R11 (a caller-saved temp register) instead of RBX (a callee-saved
register).

I believe this only affects linux/amd64, since it is the only platform
with a non-trivial cgoSigtramp implementation.

Updates #18328.

Change-Id: I3d35c4512624184d5a8ece653fa09ddf50e079a2
Reviewed-on: https://go-review.googlesource.com/35068
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
@golang golang locked and limited conversation to collaborators Jan 11, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

2 participants