[PATCH] asan: handle SIGABRT

Todd Lipcon tlipcon at gmail.com
Wed Jul 10 15:46:18 PDT 2013


Hi samsonov,

commit 0eb8067bfe9ee4848df03469ccd1a8f9364df4a5
Author: Todd Lipcon <todd at cloudera.com>
Date:   Wed Jul 10 15:34:15 2013 -0700

    asan: handle SIGABRT
    
    On some kernel versions, if /proc/sys/vm/core_pattern is set to
    a pipe, then the setrlimit(RLIMIT_CORE) call to disable core
    dumps has no effect. In that case, if the user application calls
    abort(), then the uncaught SIGABRT triggers a core dump, resulting
    in a multi-TB pipe into the core dump handler (blocking the process
    for many hours).
    
    This patch adds a handler for SIGABRT which logs the error, then
    unmaps the shadow memory before propagating the signal. This allows
    a core dump to be processed reasonably even on 64-bit systems.
    
    Manually tested with an application which calls "abort()". On systems
    set up as described above, this used to hang for hours as it tried
    to send the large core dump through the pipe. With the patch, it
    outputs:
    
    $ ./coredump
    ASAN:SIGABRT
    ==28640==ERROR: AddressSanitizer: ABRT (pc 0x7f8632666425 sp 0x7fff0cae8f08 bp 0x7fff0cae91d0 T0)
        #0 0x7f8632666424 (/lib/x86_64-linux-gnu/libc-2.15.so+0x36424)
        #1 0x7f8632669b8a (/lib/x86_64-linux-gnu/libc-2.15.so+0x39b8a)
        #2 0x42b11e (/tmp/coredump+0x42b11e)
        #3 0x7f863265176c (/lib/x86_64-linux-gnu/libc-2.15.so+0x2176c)
        #4 0x42ae7c (/tmp/coredump+0x42ae7c)
    Aborted (core dumped)


http://llvm-reviews.chandlerc.com/D1123

Files:
  lib/asan/asan_flags.h
  lib/asan/asan_linux.cc
  lib/asan/asan_mapping.h
  lib/asan/asan_posix.cc
  lib/asan/asan_report.cc
  lib/asan/asan_report.h
  lib/asan/asan_rtl.cc

Index: lib/asan/asan_flags.h
===================================================================
--- lib/asan/asan_flags.h
+++ lib/asan/asan_flags.h
@@ -71,6 +71,8 @@
   int  sleep_before_dying;
   // If set, registers ASan custom segv handler.
   bool handle_segv;
+  // If set, registers ASan custom abrt handler.
+  bool handle_abrt;
   // If set, allows user register segv handler even if ASan registers one.
   bool allow_user_segv_handler;
   // If set, uses alternate stack for signal handling.
Index: lib/asan/asan_linux.cc
===================================================================
--- lib/asan/asan_linux.cc
+++ lib/asan/asan_linux.cc
@@ -95,7 +95,8 @@
 }
 
 bool AsanInterceptsSignal(int signum) {
-  return signum == SIGSEGV && flags()->handle_segv;
+  return (signum == SIGSEGV && flags()->handle_segv) ||
+         (signum == SIGABRT && flags()->handle_abrt);
 }
 
 void AsanPlatformThreadInit() {
Index: lib/asan/asan_mapping.h
===================================================================
--- lib/asan/asan_mapping.h
+++ lib/asan/asan_mapping.h
@@ -216,6 +216,15 @@
   return false;
 }
 
+static inline void UnmapShadowMappings() {
+  if (kMidMemBeg) {
+    UnmapOrDie((void*)kLowShadowBeg, kMidMemBeg - kLowShadowBeg);
+    UnmapOrDie((void*)kMidMemEnd, kHighShadowEnd - kMidMemEnd);
+  } else {
+    UnmapOrDie((void*)kLowShadowBeg, kHighShadowEnd - kLowShadowBeg);
+  }
+}
+
 // Must be after all calls to PROFILE_ASAN_MAPPING().
 static const uptr kAsanMappingProfileSize = __LINE__;
 
Index: lib/asan/asan_posix.cc
===================================================================
--- lib/asan/asan_posix.cc
+++ lib/asan/asan_posix.cc
@@ -58,6 +58,38 @@
   ReportSIGSEGV(pc, sp, bp, addr);
 }
 
+// Invoke the default signal handler.
+void InvokeDefaultSignalHandler(int signal_number) {
+  struct sigaction sig_action;
+  REAL(memset)(&sig_action, 0, sizeof(sig_action));
+  sigemptyset(&sig_action.sa_mask);
+  sig_action.sa_handler = SIG_DFL;
+  if (flags()->use_sigaltstack) sig_action.sa_flags |= SA_ONSTACK;
+  CHECK_EQ(0, REAL(sigaction)(signal_number, &sig_action, NULL));
+}
+
+static void ASAN_OnSIGABRT(int, siginfo_t *siginfo, void *context) {
+  static atomic_uint32_t num_calls;
+  if (atomic_fetch_add(&num_calls, 1, memory_order_relaxed) != 0) {
+    Report("Reentrant call into SIGABRT handler");
+    // we may end up with a reentrant call if the munmap() calls
+    // below fail. In that case, we should ignore the reentrant
+    // failure since we're in the process of exiting anyway.
+    return;
+  }
+
+  // Write the first message using the bullet-proof write.
+  if (13 != internal_write(2, "ASAN:SIGABRT\n", 13)) Die();
+  uptr pc, sp, bp;
+  GetPcSpBp(context, &pc, &sp, &bp);
+  ReportSIGABRT(pc, sp, bp);
+
+  // Unmap the shadow pages so that a core dump is reasonable,
+  // then call through to the original SIGABRT handler
+  UnmapShadowMappings();
+  InvokeDefaultSignalHandler(SIGABRT);
+}
+
 void SetAlternateSignalStack() {
   stack_t altstack, oldstack;
   CHECK_EQ(0, sigaltstack(0, &oldstack));
@@ -94,6 +126,7 @@
   if (flags()->use_sigaltstack) SetAlternateSignalStack();
   MaybeInstallSigaction(SIGSEGV, ASAN_OnSIGSEGV);
   MaybeInstallSigaction(SIGBUS, ASAN_OnSIGSEGV);
+  MaybeInstallSigaction(SIGABRT, ASAN_OnSIGABRT);
 }
 
 // ---------------------- TSD ---------------- {{{1
Index: lib/asan/asan_report.cc
===================================================================
--- lib/asan/asan_report.cc
+++ lib/asan/asan_report.cc
@@ -523,6 +523,19 @@
   ReportSummary("SEGV", &stack);
 }
 
+void ReportSIGABRT(uptr pc, uptr sp, uptr bp) {
+  Decorator d;
+  Printf("%s", d.Warning());
+  Report("ERROR: AddressSanitizer: ABRT"
+             " (pc %p sp %p bp %p T%d)\n",
+             (void*)pc, (void*)sp, (void*)bp,
+             GetCurrentTidOrInvalid());
+  Printf("%s", d.EndWarning());
+  GET_STACK_TRACE_FATAL(pc, bp);
+  PrintStack(&stack);
+  ReportSummary("ABRT", &stack);
+}
+
 void ReportDoubleFree(uptr addr, StackTrace *stack) {
   ScopedInErrorReport in_report;
   Decorator d;
Index: lib/asan/asan_report.h
===================================================================
--- lib/asan/asan_report.h
+++ lib/asan/asan_report.h
@@ -33,6 +33,7 @@
 
 // Different kinds of error reports.
 void NORETURN ReportSIGSEGV(uptr pc, uptr sp, uptr bp, uptr addr);
+void ReportSIGABRT(uptr pc, uptr sp, uptr bp);
 void NORETURN ReportDoubleFree(uptr addr, StackTrace *stack);
 void NORETURN ReportFreeNotMalloced(uptr addr, StackTrace *stack);
 void NORETURN ReportAllocTypeMismatch(uptr addr, StackTrace *stack,
Index: lib/asan/asan_rtl.cc
===================================================================
--- lib/asan/asan_rtl.cc
+++ lib/asan/asan_rtl.cc
@@ -40,12 +40,7 @@
     SleepForSeconds(flags()->sleep_before_dying);
   }
   if (flags()->unmap_shadow_on_exit) {
-    if (kMidMemBeg) {
-      UnmapOrDie((void*)kLowShadowBeg, kMidMemBeg - kLowShadowBeg);
-      UnmapOrDie((void*)kMidMemEnd, kHighShadowEnd - kMidMemEnd);
-    } else {
-      UnmapOrDie((void*)kLowShadowBeg, kHighShadowEnd - kLowShadowBeg);
-    }
+    UnmapShadowMappings();
   }
   if (death_callback)
     death_callback();
@@ -107,6 +102,7 @@
   ParseFlag(str, &f->allow_user_poisoning, "allow_user_poisoning");
   ParseFlag(str, &f->sleep_before_dying, "sleep_before_dying");
   ParseFlag(str, &f->handle_segv, "handle_segv");
+  ParseFlag(str, &f->handle_abrt, "handle_abrt");
   ParseFlag(str, &f->allow_user_segv_handler, "allow_user_segv_handler");
   ParseFlag(str, &f->use_sigaltstack, "use_sigaltstack");
   ParseFlag(str, &f->check_malloc_usable_size, "check_malloc_usable_size");
@@ -152,6 +148,7 @@
   f->allow_user_poisoning = true;
   f->sleep_before_dying = 0;
   f->handle_segv = ASAN_NEEDS_SEGV;
+  f->handle_abrt = ASAN_NEEDS_SEGV;
   f->allow_user_segv_handler = false;
   f->use_sigaltstack = false;
   f->check_malloc_usable_size = true;
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D1123.1.patch
Type: text/x-patch
Size: 5936 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20130710/e81805ba/attachment.bin>


More information about the llvm-commits mailing list