Home | History | Annotate | Download | only in asan
      1 //===-- asan_report.cc ----------------------------------------------------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 // This file is a part of AddressSanitizer, an address sanity checker.
     11 //
     12 // This file contains error reporting code.
     13 //===----------------------------------------------------------------------===//
     14 #include "asan_flags.h"
     15 #include "asan_internal.h"
     16 #include "asan_mapping.h"
     17 #include "asan_report.h"
     18 #include "asan_stack.h"
     19 #include "asan_thread.h"
     20 #include "asan_thread_registry.h"
     21 
     22 namespace __asan {
     23 
     24 // -------------------- User-specified callbacks ----------------- {{{1
     25 static void (*error_report_callback)(const char*);
     26 static char *error_message_buffer = 0;
     27 static uptr error_message_buffer_pos = 0;
     28 static uptr error_message_buffer_size = 0;
     29 
     30 void AppendToErrorMessageBuffer(const char *buffer) {
     31   if (error_message_buffer) {
     32     uptr length = internal_strlen(buffer);
     33     CHECK_GE(error_message_buffer_size, error_message_buffer_pos);
     34     uptr remaining = error_message_buffer_size - error_message_buffer_pos;
     35     internal_strncpy(error_message_buffer + error_message_buffer_pos,
     36                      buffer, remaining);
     37     error_message_buffer[error_message_buffer_size - 1] = '\0';
     38     // FIXME: reallocate the buffer instead of truncating the message.
     39     error_message_buffer_pos += remaining > length ? length : remaining;
     40   }
     41 }
     42 
     43 static void (*on_error_callback)(void);
     44 
     45 // ---------------------- Helper functions ----------------------- {{{1
     46 
     47 static void PrintBytes(const char *before, uptr *a) {
     48   u8 *bytes = (u8*)a;
     49   uptr byte_num = (__WORDSIZE) / 8;
     50   Printf("%s%p:", before, (void*)a);
     51   for (uptr i = 0; i < byte_num; i++) {
     52     Printf(" %x%x", bytes[i] >> 4, bytes[i] & 15);
     53   }
     54   Printf("\n");
     55 }
     56 
     57 static void PrintShadowMemoryForAddress(uptr addr) {
     58   if (!AddrIsInMem(addr))
     59     return;
     60   uptr shadow_addr = MemToShadow(addr);
     61   Printf("Shadow byte and word:\n");
     62   Printf("  %p: %x\n", (void*)shadow_addr, *(unsigned char*)shadow_addr);
     63   uptr aligned_shadow = shadow_addr & ~(kWordSize - 1);
     64   PrintBytes("  ", (uptr*)(aligned_shadow));
     65   Printf("More shadow bytes:\n");
     66   for (int i = -4; i <= 4; i++) {
     67     const char *prefix = (i == 0) ? "=>" : "  ";
     68     PrintBytes(prefix, (uptr*)(aligned_shadow + i * kWordSize));
     69   }
     70 }
     71 
     72 static void PrintZoneForPointer(uptr ptr, uptr zone_ptr,
     73                                 const char *zone_name) {
     74   if (zone_ptr) {
     75     if (zone_name) {
     76       Printf("malloc_zone_from_ptr(%p) = %p, which is %s\n",
     77                  ptr, zone_ptr, zone_name);
     78     } else {
     79       Printf("malloc_zone_from_ptr(%p) = %p, which doesn't have a name\n",
     80                  ptr, zone_ptr);
     81     }
     82   } else {
     83     Printf("malloc_zone_from_ptr(%p) = 0\n", ptr);
     84   }
     85 }
     86 
     87 // ---------------------- Address Descriptions ------------------- {{{1
     88 
     89 static bool IsASCII(unsigned char c) {
     90   return /*0x00 <= c &&*/ c <= 0x7F;
     91 }
     92 
     93 // Check if the global is a zero-terminated ASCII string. If so, print it.
     94 static void PrintGlobalNameIfASCII(const __asan_global &g) {
     95   for (uptr p = g.beg; p < g.beg + g.size - 1; p++) {
     96     if (!IsASCII(*(unsigned char*)p)) return;
     97   }
     98   if (*(char*)(g.beg + g.size - 1) != 0) return;
     99   Printf("  '%s' is ascii string '%s'\n", g.name, (char*)g.beg);
    100 }
    101 
    102 bool DescribeAddressRelativeToGlobal(uptr addr, const __asan_global &g) {
    103   if (addr < g.beg - kGlobalAndStackRedzone) return false;
    104   if (addr >= g.beg + g.size_with_redzone) return false;
    105   Printf("%p is located ", (void*)addr);
    106   if (addr < g.beg) {
    107     Printf("%zd bytes to the left", g.beg - addr);
    108   } else if (addr >= g.beg + g.size) {
    109     Printf("%zd bytes to the right", addr - (g.beg + g.size));
    110   } else {
    111     Printf("%zd bytes inside", addr - g.beg);  // Can it happen?
    112   }
    113   Printf(" of global variable '%s' (0x%zx) of size %zu\n",
    114              g.name, g.beg, g.size);
    115   PrintGlobalNameIfASCII(g);
    116   return true;
    117 }
    118 
    119 bool DescribeAddressIfShadow(uptr addr) {
    120   if (AddrIsInMem(addr))
    121     return false;
    122   static const char kAddrInShadowReport[] =
    123       "Address %p is located in the %s.\n";
    124   if (AddrIsInShadowGap(addr)) {
    125     Printf(kAddrInShadowReport, addr, "shadow gap area");
    126     return true;
    127   }
    128   if (AddrIsInHighShadow(addr)) {
    129     Printf(kAddrInShadowReport, addr, "high shadow area");
    130     return true;
    131   }
    132   if (AddrIsInLowShadow(addr)) {
    133     Printf(kAddrInShadowReport, addr, "low shadow area");
    134     return true;
    135   }
    136   CHECK(0 && "Address is not in memory and not in shadow?");
    137   return false;
    138 }
    139 
    140 bool DescribeAddressIfStack(uptr addr, uptr access_size) {
    141   AsanThread *t = asanThreadRegistry().FindThreadByStackAddress(addr);
    142   if (!t) return false;
    143   const sptr kBufSize = 4095;
    144   char buf[kBufSize];
    145   uptr offset = 0;
    146   const char *frame_descr = t->GetFrameNameByAddr(addr, &offset);
    147   // This string is created by the compiler and has the following form:
    148   // "FunctioName n alloc_1 alloc_2 ... alloc_n"
    149   // where alloc_i looks like "offset size len ObjectName ".
    150   CHECK(frame_descr);
    151   // Report the function name and the offset.
    152   const char *name_end = internal_strchr(frame_descr, ' ');
    153   CHECK(name_end);
    154   buf[0] = 0;
    155   internal_strncat(buf, frame_descr,
    156                    Min(kBufSize,
    157                        static_cast<sptr>(name_end - frame_descr)));
    158   Printf("Address %p is located at offset %zu "
    159              "in frame <%s> of T%d's stack:\n",
    160              (void*)addr, offset, buf, t->tid());
    161   // Report the number of stack objects.
    162   char *p;
    163   uptr n_objects = internal_simple_strtoll(name_end, &p, 10);
    164   CHECK(n_objects > 0);
    165   Printf("  This frame has %zu object(s):\n", n_objects);
    166   // Report all objects in this frame.
    167   for (uptr i = 0; i < n_objects; i++) {
    168     uptr beg, size;
    169     sptr len;
    170     beg  = internal_simple_strtoll(p, &p, 10);
    171     size = internal_simple_strtoll(p, &p, 10);
    172     len  = internal_simple_strtoll(p, &p, 10);
    173     if (beg <= 0 || size <= 0 || len < 0 || *p != ' ') {
    174       Printf("AddressSanitizer can't parse the stack frame "
    175                  "descriptor: |%s|\n", frame_descr);
    176       break;
    177     }
    178     p++;
    179     buf[0] = 0;
    180     internal_strncat(buf, p, Min(kBufSize, len));
    181     p += len;
    182     Printf("    [%zu, %zu) '%s'\n", beg, beg + size, buf);
    183   }
    184   Printf("HINT: this may be a false positive if your program uses "
    185              "some custom stack unwind mechanism\n"
    186              "      (longjmp and C++ exceptions *are* supported)\n");
    187   DescribeThread(t->summary());
    188   return true;
    189 }
    190 
    191 void DescribeAddress(uptr addr, uptr access_size) {
    192   // Check if this is shadow or shadow gap.
    193   if (DescribeAddressIfShadow(addr))
    194     return;
    195   CHECK(AddrIsInMem(addr));
    196   if (DescribeAddressIfGlobal(addr))
    197     return;
    198   if (DescribeAddressIfStack(addr, access_size))
    199     return;
    200   // Assume it is a heap address.
    201   DescribeHeapAddress(addr, access_size);
    202 }
    203 
    204 // ------------------- Thread description -------------------- {{{1
    205 
    206 void DescribeThread(AsanThreadSummary *summary) {
    207   CHECK(summary);
    208   // No need to announce the main thread.
    209   if (summary->tid() == 0 || summary->announced()) {
    210     return;
    211   }
    212   summary->set_announced(true);
    213   Printf("Thread T%d created by T%d here:\n",
    214          summary->tid(), summary->parent_tid());
    215   PrintStack(summary->stack());
    216   // Recursively described parent thread if needed.
    217   if (flags()->print_full_thread_history) {
    218     AsanThreadSummary *parent_summary =
    219         asanThreadRegistry().FindByTid(summary->parent_tid());
    220     DescribeThread(parent_summary);
    221   }
    222 }
    223 
    224 // -------------------- Different kinds of reports ----------------- {{{1
    225 
    226 // Use ScopedInErrorReport to run common actions just before and
    227 // immediately after printing error report.
    228 class ScopedInErrorReport {
    229  public:
    230   ScopedInErrorReport() {
    231     static atomic_uint32_t num_calls;
    232     if (atomic_fetch_add(&num_calls, 1, memory_order_relaxed) != 0) {
    233       // Do not print more than one report, otherwise they will mix up.
    234       // Error reporting functions shouldn't return at this situation, as
    235       // they are defined as no-return.
    236       Report("AddressSanitizer: while reporting a bug found another one."
    237                  "Ignoring.\n");
    238       // We can't use infinite busy loop here, as ASan may try to report an
    239       // error while another error report is being printed (e.g. if the code
    240       // that prints error report for buffer overflow results in SEGV).
    241       SleepForSeconds(Max(5, flags()->sleep_before_dying + 1));
    242       Die();
    243     }
    244     if (on_error_callback) {
    245       on_error_callback();
    246     }
    247     Printf("===================================================="
    248                "=============\n");
    249     AsanThread *curr_thread = asanThreadRegistry().GetCurrent();
    250     if (curr_thread) {
    251       // We started reporting an error message. Stop using the fake stack
    252       // in case we call an instrumented function from a symbolizer.
    253       curr_thread->fake_stack().StopUsingFakeStack();
    254     }
    255   }
    256   // Destructor is NORETURN, as functions that report errors are.
    257   NORETURN ~ScopedInErrorReport() {
    258     // Make sure the current thread is announced.
    259     AsanThread *curr_thread = asanThreadRegistry().GetCurrent();
    260     if (curr_thread) {
    261       DescribeThread(curr_thread->summary());
    262     }
    263     // Print memory stats.
    264     __asan_print_accumulated_stats();
    265     if (error_report_callback) {
    266       error_report_callback(error_message_buffer);
    267     }
    268     Report("ABORTING\n");
    269     Die();
    270   }
    271 };
    272 
    273 #pragma clang diagnostic push
    274 #pragma clang diagnostic ignored "-Winvalid-noreturn"
    275 
    276 void ReportSIGSEGV(uptr pc, uptr sp, uptr bp, uptr addr) {
    277   ScopedInErrorReport in_report;
    278   Report("ERROR: AddressSanitizer crashed on unknown address %p"
    279              " (pc %p sp %p bp %p T%d)\n",
    280              (void*)addr, (void*)pc, (void*)sp, (void*)bp,
    281              asanThreadRegistry().GetCurrentTidOrInvalid());
    282   Printf("AddressSanitizer can not provide additional info.\n");
    283   GET_STACK_TRACE_WITH_PC_AND_BP(kStackTraceMax, pc, bp);
    284   PrintStack(&stack);
    285 }
    286 
    287 void ReportDoubleFree(uptr addr, StackTrace *stack) {
    288   ScopedInErrorReport in_report;
    289   Report("ERROR: AddressSanitizer attempting double-free on %p:\n", addr);
    290   PrintStack(stack);
    291   DescribeHeapAddress(addr, 1);
    292 }
    293 
    294 void ReportFreeNotMalloced(uptr addr, StackTrace *stack) {
    295   ScopedInErrorReport in_report;
    296   Report("ERROR: AddressSanitizer attempting free on address "
    297              "which was not malloc()-ed: %p\n", addr);
    298   PrintStack(stack);
    299   DescribeHeapAddress(addr, 1);
    300 }
    301 
    302 void ReportMallocUsableSizeNotOwned(uptr addr, StackTrace *stack) {
    303   ScopedInErrorReport in_report;
    304   Report("ERROR: AddressSanitizer attempting to call "
    305              "malloc_usable_size() for pointer which is "
    306              "not owned: %p\n", addr);
    307   PrintStack(stack);
    308   DescribeHeapAddress(addr, 1);
    309 }
    310 
    311 void ReportAsanGetAllocatedSizeNotOwned(uptr addr, StackTrace *stack) {
    312   ScopedInErrorReport in_report;
    313   Report("ERROR: AddressSanitizer attempting to call "
    314              "__asan_get_allocated_size() for pointer which is "
    315              "not owned: %p\n", addr);
    316   PrintStack(stack);
    317   DescribeHeapAddress(addr, 1);
    318 }
    319 
    320 void ReportStringFunctionMemoryRangesOverlap(
    321     const char *function, const char *offset1, uptr length1,
    322     const char *offset2, uptr length2, StackTrace *stack) {
    323   ScopedInErrorReport in_report;
    324   Report("ERROR: AddressSanitizer %s-param-overlap: "
    325              "memory ranges [%p,%p) and [%p, %p) overlap\n", \
    326              function, offset1, offset1 + length1, offset2, offset2 + length2);
    327   PrintStack(stack);
    328   DescribeAddress((uptr)offset1, length1);
    329   DescribeAddress((uptr)offset2, length2);
    330 }
    331 
    332 #pragma clang diagnostic pop
    333 
    334 // ----------------------- Mac-specific reports ----------------- {{{1
    335 
    336 void WarnMacFreeUnallocated(
    337     uptr addr, uptr zone_ptr, const char *zone_name, StackTrace *stack) {
    338   // Just print a warning here.
    339   Printf("free_common(%p) -- attempting to free unallocated memory.\n"
    340              "AddressSanitizer is ignoring this error on Mac OS now.\n",
    341              addr);
    342   PrintZoneForPointer(addr, zone_ptr, zone_name);
    343   PrintStack(stack);
    344   DescribeHeapAddress(addr, 1);
    345 }
    346 
    347 #pragma clang diagnostic push
    348 #pragma clang diagnostic ignored "-Winvalid-noreturn"
    349 
    350 void ReportMacMzReallocUnknown(
    351     uptr addr, uptr zone_ptr, const char *zone_name, StackTrace *stack) {
    352   ScopedInErrorReport in_report;
    353   Printf("mz_realloc(%p) -- attempting to realloc unallocated memory.\n"
    354              "This is an unrecoverable problem, exiting now.\n",
    355              addr);
    356   PrintZoneForPointer(addr, zone_ptr, zone_name);
    357   PrintStack(stack);
    358   DescribeHeapAddress(addr, 1);
    359 }
    360 
    361 void ReportMacCfReallocUnknown(
    362     uptr addr, uptr zone_ptr, const char *zone_name, StackTrace *stack) {
    363   ScopedInErrorReport in_report;
    364   Printf("cf_realloc(%p) -- attempting to realloc unallocated memory.\n"
    365              "This is an unrecoverable problem, exiting now.\n",
    366              addr);
    367   PrintZoneForPointer(addr, zone_ptr, zone_name);
    368   PrintStack(stack);
    369   DescribeHeapAddress(addr, 1);
    370 }
    371 
    372 #pragma clang diagnostic pop
    373 
    374 }  // namespace __asan
    375 
    376 // --------------------------- Interface --------------------- {{{1
    377 using namespace __asan;  // NOLINT
    378 
    379 void __asan_report_error(uptr pc, uptr bp, uptr sp,
    380                          uptr addr, bool is_write, uptr access_size) {
    381   ScopedInErrorReport in_report;
    382 
    383   // Determine the error type.
    384   const char *bug_descr = "unknown-crash";
    385   if (AddrIsInMem(addr)) {
    386     u8 *shadow_addr = (u8*)MemToShadow(addr);
    387     // If we are accessing 16 bytes, look at the second shadow byte.
    388     if (*shadow_addr == 0 && access_size > SHADOW_GRANULARITY)
    389       shadow_addr++;
    390     // If we are in the partial right redzone, look at the next shadow byte.
    391     if (*shadow_addr > 0 && *shadow_addr < 128)
    392       shadow_addr++;
    393     switch (*shadow_addr) {
    394       case kAsanHeapLeftRedzoneMagic:
    395       case kAsanHeapRightRedzoneMagic:
    396         bug_descr = "heap-buffer-overflow";
    397         break;
    398       case kAsanHeapFreeMagic:
    399         bug_descr = "heap-use-after-free";
    400         break;
    401       case kAsanStackLeftRedzoneMagic:
    402         bug_descr = "stack-buffer-underflow";
    403         break;
    404       case kAsanInitializationOrderMagic:
    405         bug_descr = "initialization-order-fiasco";
    406         break;
    407       case kAsanStackMidRedzoneMagic:
    408       case kAsanStackRightRedzoneMagic:
    409       case kAsanStackPartialRedzoneMagic:
    410         bug_descr = "stack-buffer-overflow";
    411         break;
    412       case kAsanStackAfterReturnMagic:
    413         bug_descr = "stack-use-after-return";
    414         break;
    415       case kAsanUserPoisonedMemoryMagic:
    416         bug_descr = "use-after-poison";
    417         break;
    418       case kAsanGlobalRedzoneMagic:
    419         bug_descr = "global-buffer-overflow";
    420         break;
    421     }
    422   }
    423 
    424   Report("ERROR: AddressSanitizer %s on address "
    425              "%p at pc 0x%zx bp 0x%zx sp 0x%zx\n",
    426              bug_descr, (void*)addr, pc, bp, sp);
    427 
    428   u32 curr_tid = asanThreadRegistry().GetCurrentTidOrInvalid();
    429   Printf("%s of size %zu at %p thread T%d\n",
    430              access_size ? (is_write ? "WRITE" : "READ") : "ACCESS",
    431              access_size, (void*)addr, curr_tid);
    432 
    433   GET_STACK_TRACE_WITH_PC_AND_BP(kStackTraceMax, pc, bp);
    434   PrintStack(&stack);
    435 
    436   DescribeAddress(addr, access_size);
    437 
    438   PrintShadowMemoryForAddress(addr);
    439 }
    440 
    441 void NOINLINE __asan_set_error_report_callback(void (*callback)(const char*)) {
    442   error_report_callback = callback;
    443   if (callback) {
    444     error_message_buffer_size = 1 << 16;
    445     error_message_buffer =
    446         (char*)MmapOrDie(error_message_buffer_size, __FUNCTION__);
    447     error_message_buffer_pos = 0;
    448   }
    449 }
    450 
    451 void NOINLINE __asan_set_on_error_callback(void (*callback)(void)) {
    452   on_error_callback = callback;
    453 }
    454