From 733162fd6c0df8bd700859974957b25045fe9ee4 Mon Sep 17 00:00:00 2001 From: James Chacon Date: Fri, 6 May 2016 11:51:56 -0700 Subject: [PATCH] runtime: prevent racefini from being invoked more than once racefini calls __tsan_fini which is C code and at the end of it invoked the standard C library exit(3) call. This has undefined behavior if invoked more than once. Specifically in C++ programs it caused static destructors to run twice. At least on glibc impls it also means the at_exit handlers list (where those are stored) also free's a list entry when it completes these. So invoking twice results in a double free at exit which trips debug memory allocation tracking. Fix all of this by using an atomic as a boolean barrier around calls to racefini being invoked > 1 time. Fixes #15578 Change-Id: I49222aa9b8ded77160931f46434c61a8379570fc Reviewed-on: https://go-review.googlesource.com/22882 Reviewed-by: Dmitry Vyukov Run-TryBot: Dmitry Vyukov TryBot-Result: Gobot Gobot --- src/runtime/race.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/runtime/race.go b/src/runtime/race.go index ecd68d80ce..42da936ddb 100644 --- a/src/runtime/race.go +++ b/src/runtime/race.go @@ -283,8 +283,16 @@ func raceinit() (gctx, pctx uintptr) { return } +var raceFiniLock mutex + //go:nosplit func racefini() { + // racefini() can only be called once to avoid races. + // This eventually (via __tsan_fini) calls C.exit which has + // undefined behavior if called more than once. If the lock is + // already held it's assumed that the first caller exits the program + // so other calls can hang forever without an issue. + lock(&raceFiniLock) racecall(&__tsan_fini, 0, 0, 0, 0) } -- 2.50.0