Skip to content

Commit 79ba1e4

Browse files
cmd/cgo: mark stub functions as no_sanitize_thread
When the generated stub functions write back the results to the stack, they can in some cases be writing to the same memory on the g0 stack. There is no race here (assuming there is no race in the Go code), but the thread sanitizer does not know that. Turn off the thread sanitizer for the stub functions to prevent false positive warnings. Current clang suggests the no_sanitize("thread") attribute, but that does not work with clang 3.6 or GCC. clang 3.6, GCC, and current clang all support the no_sanitize_thread attribute, so use that unconditionally. The test case and first version of the patch are from Dmitriy Vyukov. Change-Id: I80ce92824c6c8cf88ea0fe44f21cf50cf62474c9 Reviewed-on: https://go-review.googlesource.com/23252 Run-TryBot: Ian Lance Taylor <[email protected]> Reviewed-by: Dmitry Vyukov <[email protected]> TryBot-Result: Gobot Gobot <[email protected]>
1 parent 0dcd330 commit 79ba1e4

File tree

3 files changed

+57
-1
lines changed

3 files changed

+57
-1
lines changed

misc/cgo/testsanitizers/test.bash

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,16 @@ if test "$tsan" = "yes"; then
134134
status=1
135135
fi
136136

137+
if ! go run tsan3.go 2>$err; then
138+
cat $err
139+
echo "FAIL: tsan3"
140+
status=1
141+
elif grep -i warning $err >/dev/null 2>&1; then
142+
cat $err
143+
echo "FAIL: tsan3"
144+
status=1
145+
fi
146+
137147
rm -f $err
138148
fi
139149

misc/cgo/testsanitizers/tsan3.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// Copyright 2016 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package main
6+
7+
// The stubs for the C functions read and write the same slot on the
8+
// g0 stack when copying arguments in and out.
9+
10+
/*
11+
#cgo CFLAGS: -fsanitize=thread
12+
#cgo LDFLAGS: -fsanitize=thread
13+
14+
int Func1() {
15+
return 0;
16+
}
17+
18+
void Func2(int x) {
19+
(void)x;
20+
}
21+
*/
22+
import "C"
23+
24+
func main() {
25+
const N = 10000
26+
done := make(chan bool, N)
27+
for i := 0; i < N; i++ {
28+
go func() {
29+
C.Func1()
30+
done <- true
31+
}()
32+
go func() {
33+
C.Func2(0)
34+
done <- true
35+
}()
36+
}
37+
for i := 0; i < 2*N; i++ {
38+
<-done
39+
}
40+
}

src/cmd/cgo/out.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,7 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
560560

561561
// Gcc wrapper unpacks the C argument struct
562562
// and calls the actual C function.
563+
fmt.Fprintf(fgcc, "CGO_NO_SANITIZE_THREAD\n")
563564
if n.AddError {
564565
fmt.Fprintf(fgcc, "int\n")
565566
} else {
@@ -635,6 +636,7 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
635636
// wrapper, we can't refer to the function, since the reference is in
636637
// a different file.
637638
func (p *Package) writeGccgoOutputFunc(fgcc *os.File, n *Name) {
639+
fmt.Fprintf(fgcc, "CGO_NO_SANITIZE_THREAD\n")
638640
if t := n.FuncType.Result; t != nil {
639641
fmt.Fprintf(fgcc, "%s\n", t.C.String())
640642
} else {
@@ -817,6 +819,7 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
817819
fmt.Fprintf(fgcch, "\nextern %s;\n", s)
818820

819821
fmt.Fprintf(fgcc, "extern void _cgoexp%s_%s(void *, int, __SIZE_TYPE__);\n", cPrefix, exp.ExpName)
822+
fmt.Fprintf(fgcc, "\nCGO_NO_SANITIZE_THREAD")
820823
fmt.Fprintf(fgcc, "\n%s\n", s)
821824
fmt.Fprintf(fgcc, "{\n")
822825
fmt.Fprintf(fgcc, "\t__SIZE_TYPE__ _cgo_ctxt = _cgo_wait_runtime_init_done();\n")
@@ -1020,7 +1023,7 @@ func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) {
10201023
fmt.Fprintf(fgcc, `extern %s %s %s __asm__("%s.%s");`, cRet, goName, cParams, gccgoSymbolPrefix, goName)
10211024
fmt.Fprint(fgcc, "\n")
10221025

1023-
fmt.Fprint(fgcc, "\n")
1026+
fmt.Fprint(fgcc, "\nCGO_NO_SANITIZE_THREAD\n")
10241027
fmt.Fprintf(fgcc, "%s %s %s {\n", cRet, exp.ExpName, cParams)
10251028
if resultCount > 0 {
10261029
fmt.Fprintf(fgcc, "\t%s r;\n", cRet)
@@ -1304,11 +1307,14 @@ extern char* _cgo_topofstack(void);
13041307

13051308
// Prologue defining TSAN functions in C.
13061309
const noTsanProlog = `
1310+
#define CGO_NO_SANITIZE_THREAD
13071311
#define _cgo_tsan_acquire()
13081312
#define _cgo_tsan_release()
13091313
`
13101314

13111315
const yesTsanProlog = `
1316+
#define CGO_NO_SANITIZE_THREAD __attribute__ ((no_sanitize_thread))
1317+
13121318
long long _cgo_sync __attribute__ ((common));
13131319
13141320
extern void __tsan_acquire(void*);

0 commit comments

Comments
 (0)