[compiler-rt] r313835 - [asan] Fix nested error detection
Vitaly Buka via llvm-commits
llvm-commits at lists.llvm.org
Wed Sep 20 16:27:38 PDT 2017
Author: vitalybuka
Date: Wed Sep 20 16:27:38 2017
New Revision: 313835
URL: http://llvm.org/viewvc/llvm-project?rev=313835&view=rev
Log:
[asan] Fix nested error detection
Summary: Fixes https://github.com/google/sanitizers/issues/858
Reviewers: eugenis, dvyukov
Subscribers: kubamracek, llvm-commits
Differential Revision: https://reviews.llvm.org/D38019
Added:
compiler-rt/trunk/test/asan/TestCases/Posix/concurrent_overflow.cc
Modified:
compiler-rt/trunk/lib/asan/asan_report.cc
Modified: compiler-rt/trunk/lib/asan/asan_report.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_report.cc?rev=313835&r1=313834&r2=313835&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_report.cc (original)
+++ compiler-rt/trunk/lib/asan/asan_report.cc Wed Sep 20 16:27:38 2017
@@ -122,53 +122,37 @@ bool ParseFrameDescription(const char *f
// immediately after printing error report.
class ScopedInErrorReport {
public:
+ static const u32 kUnclaimedTid = 0xfffffe;
+ static_assert(kUnclaimedTid != kInvalidTid, "Must be different");
+
explicit ScopedInErrorReport(bool fatal = false) {
halt_on_error_ = fatal || flags()->halt_on_error;
-
- if (lock_.TryLock()) {
- StartReporting();
- return;
- }
-
- // ASan found two bugs in different threads simultaneously.
-
u32 current_tid = GetCurrentTidOrInvalid();
- if (reporting_thread_tid_ == current_tid ||
- reporting_thread_tid_ == kInvalidTid) {
- // This is either asynch signal or nested error during error reporting.
- // Fail simple to avoid deadlocks in Report().
-
- // Can't use Report() here because of potential deadlocks
- // in nested signal handlers.
- static const char msg[] =
- "AddressSanitizer: nested bug in the same thread, aborting.\n";
- CatastrophicErrorWrite(msg, sizeof(msg) - 1);
- internal__exit(common_flags()->exitcode);
- }
+ for (;;) {
+ u32 expected_tid = kUnclaimedTid;
+ if (atomic_compare_exchange_strong(&reporting_thread_tid_, &expected_tid,
+ current_tid, memory_order_relaxed)) {
+ // We've claimed reporting_thread_tid_ so proceed.
+ StartReporting();
+ return;
+ }
+
+ if (expected_tid == current_tid) {
+ // This is either asynch signal or nested error during error reporting.
+ // Fail simple to avoid deadlocks in Report().
+
+ // Can't use Report() here because of potential deadlocks in nested
+ // signal handlers.
+ static const char msg[] =
+ "AddressSanitizer: nested bug in the same thread, aborting.\n";
+ CatastrophicErrorWrite(msg, sizeof(msg) - 1);
- if (halt_on_error_) {
- // Do not print more than one report, otherwise they will mix up.
- // Error reporting functions shouldn't return at this situation, as
- // they are effectively no-returns.
-
- Report("AddressSanitizer: while reporting a bug found another one. "
- "Ignoring.\n");
-
- // Sleep long enough to make sure that the thread which started
- // to print an error report will finish doing it.
- SleepForSeconds(Max(100, flags()->sleep_before_dying + 1));
-
- // If we're still not dead for some reason, use raw _exit() instead of
- // Die() to bypass any additional checks.
- internal__exit(common_flags()->exitcode);
- } else {
- // The other thread will eventually finish reporting
- // so it's safe to wait
- lock_.Lock();
- }
+ internal__exit(common_flags()->exitcode);
+ }
- StartReporting();
+ SleepForMillis(100);
+ }
}
~ScopedInErrorReport() {
@@ -216,13 +200,13 @@ class ScopedInErrorReport {
if (!halt_on_error_)
internal_memset(¤t_error_, 0, sizeof(current_error_));
- CommonSanitizerReportMutex.Unlock();
- reporting_thread_tid_ = kInvalidTid;
- lock_.Unlock();
if (halt_on_error_) {
Report("ABORTING\n");
Die();
}
+
+ atomic_store_relaxed(&reporting_thread_tid_, kUnclaimedTid);
+ CommonSanitizerReportMutex.Unlock();
}
void ReportError(const ErrorDescription &description) {
@@ -237,27 +221,24 @@ class ScopedInErrorReport {
private:
void StartReporting() {
+ CommonSanitizerReportMutex.Lock();
// Make sure the registry and sanitizer report mutexes are locked while
// we're printing an error report.
// We can lock them only here to avoid self-deadlock in case of
// recursive reports.
asanThreadRegistry().Lock();
- CommonSanitizerReportMutex.Lock();
- reporting_thread_tid_ = GetCurrentTidOrInvalid();
- Printf("===================================================="
- "=============\n");
+ Printf(
+ "=================================================================\n");
}
- static StaticSpinMutex lock_;
- static u32 reporting_thread_tid_;
+ static atomic_uint32_t reporting_thread_tid_;
// Error currently being reported. This enables the destructor to interact
// with the debugger and point it to an error description.
static ErrorDescription current_error_;
bool halt_on_error_;
};
-StaticSpinMutex ScopedInErrorReport::lock_;
-u32 ScopedInErrorReport::reporting_thread_tid_ = kInvalidTid;
+atomic_uint32_t ScopedInErrorReport::reporting_thread_tid_ = {kUnclaimedTid};
ErrorDescription ScopedInErrorReport::current_error_;
void ReportDeadlySignal(const SignalContext &sig) {
Added: compiler-rt/trunk/test/asan/TestCases/Posix/concurrent_overflow.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/asan/TestCases/Posix/concurrent_overflow.cc?rev=313835&view=auto
==============================================================================
--- compiler-rt/trunk/test/asan/TestCases/Posix/concurrent_overflow.cc (added)
+++ compiler-rt/trunk/test/asan/TestCases/Posix/concurrent_overflow.cc Wed Sep 20 16:27:38 2017
@@ -0,0 +1,33 @@
+// RUN: %clangxx_asan -O0 -w %s -o %t && not %run %t 2>&1 | FileCheck %s
+
+// Checks that concurrent reports will not trigger false "nested bug" reports.
+// Regression test for https://github.com/google/sanitizers/issues/858
+
+#include <pthread.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+static void *start_routine(void *arg) {
+ volatile int *counter = (volatile int *)arg;
+ char buf[8];
+ __atomic_sub_fetch(counter, 1, __ATOMIC_SEQ_CST);
+ while (*counter)
+ ;
+ buf[0] = buf[9];
+ return 0;
+}
+
+int main(void) {
+ const int n_threads = 8;
+ int i, counter = n_threads;
+ pthread_t thread;
+
+ for (i = 0; i < n_threads; ++i)
+ pthread_create(&thread, NULL, &start_routine, (void *)&counter);
+ sleep(5);
+ return 0;
+}
+
+// CHECK-NOT: nested bug
+// CHECK: ERROR: AddressSanitizer: stack-buffer-overflow on address
+// CHECK: SUMMARY: AddressSanitizer: stack-buffer-overflow
More information about the llvm-commits
mailing list