mirror of
https://github.com/golang/go
synced 2024-11-13 17:30:24 -07:00
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 <iant@golang.org> Reviewed-by: Dmitry Vyukov <dvyukov@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
parent
0dcd330bc8
commit
79ba1e44c7
@ -134,6 +134,16 @@ if test "$tsan" = "yes"; then
|
|||||||
status=1
|
status=1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if ! go run tsan3.go 2>$err; then
|
||||||
|
cat $err
|
||||||
|
echo "FAIL: tsan3"
|
||||||
|
status=1
|
||||||
|
elif grep -i warning $err >/dev/null 2>&1; then
|
||||||
|
cat $err
|
||||||
|
echo "FAIL: tsan3"
|
||||||
|
status=1
|
||||||
|
fi
|
||||||
|
|
||||||
rm -f $err
|
rm -f $err
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
40
misc/cgo/testsanitizers/tsan3.go
Normal file
40
misc/cgo/testsanitizers/tsan3.go
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
// Copyright 2016 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.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
// The stubs for the C functions read and write the same slot on the
|
||||||
|
// g0 stack when copying arguments in and out.
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo CFLAGS: -fsanitize=thread
|
||||||
|
#cgo LDFLAGS: -fsanitize=thread
|
||||||
|
|
||||||
|
int Func1() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Func2(int x) {
|
||||||
|
(void)x;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
const N = 10000
|
||||||
|
done := make(chan bool, N)
|
||||||
|
for i := 0; i < N; i++ {
|
||||||
|
go func() {
|
||||||
|
C.Func1()
|
||||||
|
done <- true
|
||||||
|
}()
|
||||||
|
go func() {
|
||||||
|
C.Func2(0)
|
||||||
|
done <- true
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
for i := 0; i < 2*N; i++ {
|
||||||
|
<-done
|
||||||
|
}
|
||||||
|
}
|
@ -560,6 +560,7 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
|
|||||||
|
|
||||||
// Gcc wrapper unpacks the C argument struct
|
// Gcc wrapper unpacks the C argument struct
|
||||||
// and calls the actual C function.
|
// and calls the actual C function.
|
||||||
|
fmt.Fprintf(fgcc, "CGO_NO_SANITIZE_THREAD\n")
|
||||||
if n.AddError {
|
if n.AddError {
|
||||||
fmt.Fprintf(fgcc, "int\n")
|
fmt.Fprintf(fgcc, "int\n")
|
||||||
} else {
|
} else {
|
||||||
@ -635,6 +636,7 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
|
|||||||
// wrapper, we can't refer to the function, since the reference is in
|
// wrapper, we can't refer to the function, since the reference is in
|
||||||
// a different file.
|
// a different file.
|
||||||
func (p *Package) writeGccgoOutputFunc(fgcc *os.File, n *Name) {
|
func (p *Package) writeGccgoOutputFunc(fgcc *os.File, n *Name) {
|
||||||
|
fmt.Fprintf(fgcc, "CGO_NO_SANITIZE_THREAD\n")
|
||||||
if t := n.FuncType.Result; t != nil {
|
if t := n.FuncType.Result; t != nil {
|
||||||
fmt.Fprintf(fgcc, "%s\n", t.C.String())
|
fmt.Fprintf(fgcc, "%s\n", t.C.String())
|
||||||
} else {
|
} else {
|
||||||
@ -817,6 +819,7 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
|
|||||||
fmt.Fprintf(fgcch, "\nextern %s;\n", s)
|
fmt.Fprintf(fgcch, "\nextern %s;\n", s)
|
||||||
|
|
||||||
fmt.Fprintf(fgcc, "extern void _cgoexp%s_%s(void *, int, __SIZE_TYPE__);\n", cPrefix, exp.ExpName)
|
fmt.Fprintf(fgcc, "extern void _cgoexp%s_%s(void *, int, __SIZE_TYPE__);\n", cPrefix, exp.ExpName)
|
||||||
|
fmt.Fprintf(fgcc, "\nCGO_NO_SANITIZE_THREAD")
|
||||||
fmt.Fprintf(fgcc, "\n%s\n", s)
|
fmt.Fprintf(fgcc, "\n%s\n", s)
|
||||||
fmt.Fprintf(fgcc, "{\n")
|
fmt.Fprintf(fgcc, "{\n")
|
||||||
fmt.Fprintf(fgcc, "\t__SIZE_TYPE__ _cgo_ctxt = _cgo_wait_runtime_init_done();\n")
|
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) {
|
|||||||
fmt.Fprintf(fgcc, `extern %s %s %s __asm__("%s.%s");`, cRet, goName, cParams, gccgoSymbolPrefix, goName)
|
fmt.Fprintf(fgcc, `extern %s %s %s __asm__("%s.%s");`, cRet, goName, cParams, gccgoSymbolPrefix, goName)
|
||||||
fmt.Fprint(fgcc, "\n")
|
fmt.Fprint(fgcc, "\n")
|
||||||
|
|
||||||
fmt.Fprint(fgcc, "\n")
|
fmt.Fprint(fgcc, "\nCGO_NO_SANITIZE_THREAD\n")
|
||||||
fmt.Fprintf(fgcc, "%s %s %s {\n", cRet, exp.ExpName, cParams)
|
fmt.Fprintf(fgcc, "%s %s %s {\n", cRet, exp.ExpName, cParams)
|
||||||
if resultCount > 0 {
|
if resultCount > 0 {
|
||||||
fmt.Fprintf(fgcc, "\t%s r;\n", cRet)
|
fmt.Fprintf(fgcc, "\t%s r;\n", cRet)
|
||||||
@ -1304,11 +1307,14 @@ extern char* _cgo_topofstack(void);
|
|||||||
|
|
||||||
// Prologue defining TSAN functions in C.
|
// Prologue defining TSAN functions in C.
|
||||||
const noTsanProlog = `
|
const noTsanProlog = `
|
||||||
|
#define CGO_NO_SANITIZE_THREAD
|
||||||
#define _cgo_tsan_acquire()
|
#define _cgo_tsan_acquire()
|
||||||
#define _cgo_tsan_release()
|
#define _cgo_tsan_release()
|
||||||
`
|
`
|
||||||
|
|
||||||
const yesTsanProlog = `
|
const yesTsanProlog = `
|
||||||
|
#define CGO_NO_SANITIZE_THREAD __attribute__ ((no_sanitize_thread))
|
||||||
|
|
||||||
long long _cgo_sync __attribute__ ((common));
|
long long _cgo_sync __attribute__ ((common));
|
||||||
|
|
||||||
extern void __tsan_acquire(void*);
|
extern void __tsan_acquire(void*);
|
||||||
|
Loading…
Reference in New Issue
Block a user