• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
AppendToErrorMessageBuffer(const char * buffer)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 
PrintBytes(const char * before,uptr * a)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 
PrintShadowMemoryForAddress(uptr addr)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 
PrintZoneForPointer(uptr ptr,uptr zone_ptr,const char * zone_name)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 
IsASCII(unsigned char c)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.
PrintGlobalNameIfASCII(const __asan_global & g)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 
DescribeAddressRelativeToGlobal(uptr addr,const __asan_global & g)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 
DescribeAddressIfShadow(uptr addr)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 
DescribeAddressIfStack(uptr addr,uptr access_size)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 
DescribeAddress(uptr addr,uptr access_size)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 
DescribeThread(AsanThreadSummary * summary)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:
ScopedInErrorReport()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.
~ScopedInErrorReport()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 
ReportSIGSEGV(uptr pc,uptr sp,uptr bp,uptr addr)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 
ReportDoubleFree(uptr addr,StackTrace * stack)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 
ReportFreeNotMalloced(uptr addr,StackTrace * stack)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 
ReportMallocUsableSizeNotOwned(uptr addr,StackTrace * stack)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 
ReportAsanGetAllocatedSizeNotOwned(uptr addr,StackTrace * stack)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 
ReportStringFunctionMemoryRangesOverlap(const char * function,const char * offset1,uptr length1,const char * offset2,uptr length2,StackTrace * stack)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 
WarnMacFreeUnallocated(uptr addr,uptr zone_ptr,const char * zone_name,StackTrace * stack)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 
ReportMacMzReallocUnknown(uptr addr,uptr zone_ptr,const char * zone_name,StackTrace * stack)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 
ReportMacCfReallocUnknown(uptr addr,uptr zone_ptr,const char * zone_name,StackTrace * stack)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 
__asan_report_error(uptr pc,uptr bp,uptr sp,uptr addr,bool is_write,uptr access_size)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 
__asan_set_error_report_callback(void (* callback)(const char *))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 
__asan_set_on_error_callback(void (* callback)(void))451 void NOINLINE __asan_set_on_error_callback(void (*callback)(void)) {
452   on_error_callback = callback;
453 }
454