Index: lib/sanitizer_common/sanitizer_common.h =================================================================== --- lib/sanitizer_common/sanitizer_common.h +++ lib/sanitizer_common/sanitizer_common.h @@ -165,7 +165,9 @@ // Specific tools may override behavior of "Die" and "CheckFailed" functions // to do tool-specific job. -void SetDieCallback(void (*callback)(void)); +typedef void (*DieCallbackType)(void); +void SetDieCallback(DieCallbackType); +DieCallbackType GetDieCallback(); typedef void (*CheckFailedCallbackType)(const char *, int, const char *, u64, u64); void SetCheckFailedCallback(CheckFailedCallbackType callback); Index: lib/sanitizer_common/sanitizer_common.cc =================================================================== --- lib/sanitizer_common/sanitizer_common.cc +++ lib/sanitizer_common/sanitizer_common.cc @@ -37,11 +37,15 @@ // child thread will be different from |report_fd_pid|. static uptr report_fd_pid = 0; -static void (*DieCallback)(void); -void SetDieCallback(void (*callback)(void)) { +static DieCallbackType DieCallback; +void SetDieCallback(DieCallbackType callback) { DieCallback = callback; } +DieCallbackType GetDieCallback() { + return DieCallback; +} + void NORETURN Die() { if (DieCallback) { DieCallback(); Index: lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc =================================================================== --- lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc +++ lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc @@ -191,6 +191,8 @@ BlockingMutex mutex; }; +static DieCallbackType old_die_callback; + // Signal handler to wake up suspended threads when the tracer thread dies. void TracerThreadSignalHandler(int signum, siginfo_t *siginfo, void *) { if (thread_suspender_instance != NULL) { @@ -202,6 +204,17 @@ internal__exit((signum == SIGABRT) ? 1 : 2); } +static void TracerThreadDieCallback() { + // This really only works correctly if all the threads are suspended at this + // point. So we correctly handle calls to Die() from within the callback, but + // not those that happen before or after the callback. Hopefully there aren't + // a lot of opportunities for that to happen... + if (thread_suspender_instance) + thread_suspender_instance->KillAllThreads(); + if (old_die_callback) + old_die_callback(); +} + // Size of alternative stack for signal handlers in the tracer thread. static const int kHandlerStackSize = 4096; @@ -214,6 +227,8 @@ tracer_thread_argument->mutex.Lock(); tracer_thread_argument->mutex.Unlock(); + SetDieCallback(TracerThreadDieCallback); + ThreadSuspender thread_suspender(internal_getppid()); // Global pointer for the signal handler. thread_suspender_instance = &thread_suspender; @@ -326,6 +341,7 @@ // Block the execution of TracerThread until after we have set ptrace // permissions. tracer_thread_argument.mutex.Lock(); + old_die_callback = GetDieCallback(); pid_t tracer_pid = clone(TracerThread, tracer_stack.Bottom(), CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_UNTRACED, &tracer_thread_argument); @@ -349,6 +365,7 @@ if (internal_iserror(waitpid_status, &wperrno)) Report("Waiting on the tracer thread failed (errno %d).\n", wperrno); } + SetDieCallback(old_die_callback); // Restore the dumpable flag. if (!process_was_dumpable) internal_prctl(PR_SET_DUMPABLE, 0, 0, 0, 0);