blob: 51b081e1534fda0615c0c24927c18710b539bd51 [file] [log] [blame]
Alexey Samsonov73545092012-08-09 07:40:58 +00001//===-- 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//===----------------------------------------------------------------------===//
Alexey Samsonov98737922012-08-10 15:13:05 +000014#include "asan_flags.h"
Alexey Samsonov73545092012-08-09 07:40:58 +000015#include "asan_internal.h"
Alexey Samsonove218beb2012-08-09 09:06:52 +000016#include "asan_mapping.h"
Alexey Samsonov73545092012-08-09 07:40:58 +000017#include "asan_report.h"
18#include "asan_stack.h"
Alexey Samsonove4bfca22012-08-09 09:27:24 +000019#include "asan_thread.h"
Alexey Samsonov73545092012-08-09 07:40:58 +000020#include "asan_thread_registry.h"
21
22namespace __asan {
23
Alexey Samsonovf657a192012-08-13 11:23:40 +000024// -------------------- User-specified callbacks ----------------- {{{1
Alexey Samsonovc98570b2012-08-09 10:56:57 +000025static void (*error_report_callback)(const char*);
26static char *error_message_buffer = 0;
27static uptr error_message_buffer_pos = 0;
28static uptr error_message_buffer_size = 0;
29
30void 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
Alexey Samsonov98737922012-08-10 15:13:05 +000043// ---------------------- Helper functions ----------------------- {{{1
44
45static void PrintBytes(const char *before, uptr *a) {
46 u8 *bytes = (u8*)a;
Kostya Serebryany5af39e52012-11-21 12:38:58 +000047 uptr byte_num = (SANITIZER_WORDSIZE) / 8;
Kostya Serebryany283c2962012-08-28 11:34:40 +000048 Printf("%s%p:", before, (void*)a);
Alexey Samsonov98737922012-08-10 15:13:05 +000049 for (uptr i = 0; i < byte_num; i++) {
Kostya Serebryany283c2962012-08-28 11:34:40 +000050 Printf(" %x%x", bytes[i] >> 4, bytes[i] & 15);
Alexey Samsonov98737922012-08-10 15:13:05 +000051 }
Kostya Serebryany283c2962012-08-28 11:34:40 +000052 Printf("\n");
Alexey Samsonov98737922012-08-10 15:13:05 +000053}
54
55static void PrintShadowMemoryForAddress(uptr addr) {
56 if (!AddrIsInMem(addr))
57 return;
58 uptr shadow_addr = MemToShadow(addr);
Kostya Serebryany283c2962012-08-28 11:34:40 +000059 Printf("Shadow byte and word:\n");
60 Printf(" %p: %x\n", (void*)shadow_addr, *(unsigned char*)shadow_addr);
Alexey Samsonov98737922012-08-10 15:13:05 +000061 uptr aligned_shadow = shadow_addr & ~(kWordSize - 1);
62 PrintBytes(" ", (uptr*)(aligned_shadow));
Kostya Serebryany283c2962012-08-28 11:34:40 +000063 Printf("More shadow bytes:\n");
Alexey Samsonov98737922012-08-10 15:13:05 +000064 for (int i = -4; i <= 4; i++) {
65 const char *prefix = (i == 0) ? "=>" : " ";
66 PrintBytes(prefix, (uptr*)(aligned_shadow + i * kWordSize));
67 }
68}
69
70static void PrintZoneForPointer(uptr ptr, uptr zone_ptr,
71 const char *zone_name) {
72 if (zone_ptr) {
73 if (zone_name) {
Kostya Serebryany283c2962012-08-28 11:34:40 +000074 Printf("malloc_zone_from_ptr(%p) = %p, which is %s\n",
Alexey Samsonov98737922012-08-10 15:13:05 +000075 ptr, zone_ptr, zone_name);
76 } else {
Kostya Serebryany283c2962012-08-28 11:34:40 +000077 Printf("malloc_zone_from_ptr(%p) = %p, which doesn't have a name\n",
Alexey Samsonov98737922012-08-10 15:13:05 +000078 ptr, zone_ptr);
79 }
80 } else {
Kostya Serebryany283c2962012-08-28 11:34:40 +000081 Printf("malloc_zone_from_ptr(%p) = 0\n", ptr);
Alexey Samsonov98737922012-08-10 15:13:05 +000082 }
83}
84
Alexey Samsonove218beb2012-08-09 09:06:52 +000085// ---------------------- Address Descriptions ------------------- {{{1
86
Alexey Samsonove4bfca22012-08-09 09:27:24 +000087static bool IsASCII(unsigned char c) {
Alexey Samsonov98737922012-08-10 15:13:05 +000088 return /*0x00 <= c &&*/ c <= 0x7F;
Alexey Samsonove4bfca22012-08-09 09:27:24 +000089}
90
91// Check if the global is a zero-terminated ASCII string. If so, print it.
92static void PrintGlobalNameIfASCII(const __asan_global &g) {
93 for (uptr p = g.beg; p < g.beg + g.size - 1; p++) {
94 if (!IsASCII(*(unsigned char*)p)) return;
95 }
96 if (*(char*)(g.beg + g.size - 1) != 0) return;
Kostya Serebryany283c2962012-08-28 11:34:40 +000097 Printf(" '%s' is ascii string '%s'\n", g.name, (char*)g.beg);
Alexey Samsonove4bfca22012-08-09 09:27:24 +000098}
99
100bool DescribeAddressRelativeToGlobal(uptr addr, const __asan_global &g) {
101 if (addr < g.beg - kGlobalAndStackRedzone) return false;
102 if (addr >= g.beg + g.size_with_redzone) return false;
Kostya Serebryany283c2962012-08-28 11:34:40 +0000103 Printf("%p is located ", (void*)addr);
Alexey Samsonove4bfca22012-08-09 09:27:24 +0000104 if (addr < g.beg) {
Kostya Serebryany283c2962012-08-28 11:34:40 +0000105 Printf("%zd bytes to the left", g.beg - addr);
Alexey Samsonove4bfca22012-08-09 09:27:24 +0000106 } else if (addr >= g.beg + g.size) {
Kostya Serebryany283c2962012-08-28 11:34:40 +0000107 Printf("%zd bytes to the right", addr - (g.beg + g.size));
Alexey Samsonove4bfca22012-08-09 09:27:24 +0000108 } else {
Kostya Serebryany283c2962012-08-28 11:34:40 +0000109 Printf("%zd bytes inside", addr - g.beg); // Can it happen?
Alexey Samsonove4bfca22012-08-09 09:27:24 +0000110 }
Kostya Serebryany283c2962012-08-28 11:34:40 +0000111 Printf(" of global variable '%s' (0x%zx) of size %zu\n",
Alexey Samsonove4bfca22012-08-09 09:27:24 +0000112 g.name, g.beg, g.size);
113 PrintGlobalNameIfASCII(g);
114 return true;
115}
116
Alexey Samsonove218beb2012-08-09 09:06:52 +0000117bool DescribeAddressIfShadow(uptr addr) {
118 if (AddrIsInMem(addr))
119 return false;
120 static const char kAddrInShadowReport[] =
121 "Address %p is located in the %s.\n";
122 if (AddrIsInShadowGap(addr)) {
Kostya Serebryany283c2962012-08-28 11:34:40 +0000123 Printf(kAddrInShadowReport, addr, "shadow gap area");
Alexey Samsonove218beb2012-08-09 09:06:52 +0000124 return true;
125 }
126 if (AddrIsInHighShadow(addr)) {
Kostya Serebryany283c2962012-08-28 11:34:40 +0000127 Printf(kAddrInShadowReport, addr, "high shadow area");
Alexey Samsonove218beb2012-08-09 09:06:52 +0000128 return true;
129 }
130 if (AddrIsInLowShadow(addr)) {
Kostya Serebryany283c2962012-08-28 11:34:40 +0000131 Printf(kAddrInShadowReport, addr, "low shadow area");
Alexey Samsonove218beb2012-08-09 09:06:52 +0000132 return true;
133 }
134 CHECK(0 && "Address is not in memory and not in shadow?");
135 return false;
136}
137
138bool DescribeAddressIfStack(uptr addr, uptr access_size) {
139 AsanThread *t = asanThreadRegistry().FindThreadByStackAddress(addr);
140 if (!t) return false;
141 const sptr kBufSize = 4095;
142 char buf[kBufSize];
143 uptr offset = 0;
144 const char *frame_descr = t->GetFrameNameByAddr(addr, &offset);
145 // This string is created by the compiler and has the following form:
146 // "FunctioName n alloc_1 alloc_2 ... alloc_n"
147 // where alloc_i looks like "offset size len ObjectName ".
148 CHECK(frame_descr);
149 // Report the function name and the offset.
150 const char *name_end = internal_strchr(frame_descr, ' ');
151 CHECK(name_end);
152 buf[0] = 0;
153 internal_strncat(buf, frame_descr,
154 Min(kBufSize,
155 static_cast<sptr>(name_end - frame_descr)));
Kostya Serebryany283c2962012-08-28 11:34:40 +0000156 Printf("Address %p is located at offset %zu "
Alexey Samsonove218beb2012-08-09 09:06:52 +0000157 "in frame <%s> of T%d's stack:\n",
158 (void*)addr, offset, buf, t->tid());
159 // Report the number of stack objects.
160 char *p;
161 uptr n_objects = internal_simple_strtoll(name_end, &p, 10);
162 CHECK(n_objects > 0);
Kostya Serebryany283c2962012-08-28 11:34:40 +0000163 Printf(" This frame has %zu object(s):\n", n_objects);
Alexey Samsonove218beb2012-08-09 09:06:52 +0000164 // Report all objects in this frame.
165 for (uptr i = 0; i < n_objects; i++) {
166 uptr beg, size;
167 sptr len;
168 beg = internal_simple_strtoll(p, &p, 10);
169 size = internal_simple_strtoll(p, &p, 10);
170 len = internal_simple_strtoll(p, &p, 10);
171 if (beg <= 0 || size <= 0 || len < 0 || *p != ' ') {
Kostya Serebryany283c2962012-08-28 11:34:40 +0000172 Printf("AddressSanitizer can't parse the stack frame "
Alexey Samsonove218beb2012-08-09 09:06:52 +0000173 "descriptor: |%s|\n", frame_descr);
174 break;
175 }
176 p++;
177 buf[0] = 0;
178 internal_strncat(buf, p, Min(kBufSize, len));
179 p += len;
Kostya Serebryany283c2962012-08-28 11:34:40 +0000180 Printf(" [%zu, %zu) '%s'\n", beg, beg + size, buf);
Alexey Samsonove218beb2012-08-09 09:06:52 +0000181 }
Kostya Serebryany283c2962012-08-28 11:34:40 +0000182 Printf("HINT: this may be a false positive if your program uses "
Alexey Samsonov08700282012-11-23 09:46:34 +0000183 "some custom stack unwind mechanism or swapcontext\n"
Alexey Samsonove218beb2012-08-09 09:06:52 +0000184 " (longjmp and C++ exceptions *are* supported)\n");
Alexey Samsonov71b42c92012-09-05 07:37:15 +0000185 DescribeThread(t->summary());
Alexey Samsonove218beb2012-08-09 09:06:52 +0000186 return true;
187}
188
Alexey Samsonov5c153fa2012-09-18 07:38:10 +0000189static void DescribeAccessToHeapChunk(AsanChunkView chunk, uptr addr,
190 uptr access_size) {
191 uptr offset;
192 Printf("%p is located ", (void*)addr);
193 if (chunk.AddrIsInside(addr, access_size, &offset)) {
194 Printf("%zu bytes inside of", offset);
195 } else if (chunk.AddrIsAtLeft(addr, access_size, &offset)) {
196 Printf("%zu bytes to the left of", offset);
197 } else if (chunk.AddrIsAtRight(addr, access_size, &offset)) {
198 Printf("%zu bytes to the right of", offset);
199 } else {
200 Printf(" somewhere around (this is AddressSanitizer bug!)");
201 }
202 Printf(" %zu-byte region [%p,%p)\n", chunk.UsedSize(),
203 (void*)(chunk.Beg()), (void*)(chunk.End()));
204}
205
206void DescribeHeapAddress(uptr addr, uptr access_size) {
207 AsanChunkView chunk = FindHeapChunkByAddress(addr);
208 if (!chunk.IsValid()) return;
209 DescribeAccessToHeapChunk(chunk, addr, access_size);
210 CHECK(chunk.AllocTid() != kInvalidTid);
211 AsanThreadSummary *alloc_thread =
212 asanThreadRegistry().FindByTid(chunk.AllocTid());
213 StackTrace alloc_stack;
214 chunk.GetAllocStack(&alloc_stack);
215 AsanThread *t = asanThreadRegistry().GetCurrent();
216 CHECK(t);
217 if (chunk.FreeTid() != kInvalidTid) {
218 AsanThreadSummary *free_thread =
219 asanThreadRegistry().FindByTid(chunk.FreeTid());
220 Printf("freed by thread T%d here:\n", free_thread->tid());
221 StackTrace free_stack;
222 chunk.GetFreeStack(&free_stack);
223 PrintStack(&free_stack);
224 Printf("previously allocated by thread T%d here:\n", alloc_thread->tid());
225 PrintStack(&alloc_stack);
226 DescribeThread(t->summary());
227 DescribeThread(free_thread);
228 DescribeThread(alloc_thread);
229 } else {
230 Printf("allocated by thread T%d here:\n", alloc_thread->tid());
231 PrintStack(&alloc_stack);
232 DescribeThread(t->summary());
233 DescribeThread(alloc_thread);
234 }
235}
236
Alexey Samsonove218beb2012-08-09 09:06:52 +0000237void DescribeAddress(uptr addr, uptr access_size) {
238 // Check if this is shadow or shadow gap.
239 if (DescribeAddressIfShadow(addr))
240 return;
241 CHECK(AddrIsInMem(addr));
242 if (DescribeAddressIfGlobal(addr))
243 return;
244 if (DescribeAddressIfStack(addr, access_size))
245 return;
246 // Assume it is a heap address.
247 DescribeHeapAddress(addr, access_size);
248}
249
Alexey Samsonov71b42c92012-09-05 07:37:15 +0000250// ------------------- Thread description -------------------- {{{1
251
252void DescribeThread(AsanThreadSummary *summary) {
253 CHECK(summary);
254 // No need to announce the main thread.
255 if (summary->tid() == 0 || summary->announced()) {
256 return;
257 }
258 summary->set_announced(true);
259 Printf("Thread T%d created by T%d here:\n",
260 summary->tid(), summary->parent_tid());
261 PrintStack(summary->stack());
262 // Recursively described parent thread if needed.
263 if (flags()->print_full_thread_history) {
264 AsanThreadSummary *parent_summary =
265 asanThreadRegistry().FindByTid(summary->parent_tid());
266 DescribeThread(parent_summary);
267 }
268}
269
Alexey Samsonove218beb2012-08-09 09:06:52 +0000270// -------------------- Different kinds of reports ----------------- {{{1
271
Alexey Samsonov98737922012-08-10 15:13:05 +0000272// Use ScopedInErrorReport to run common actions just before and
273// immediately after printing error report.
274class ScopedInErrorReport {
275 public:
276 ScopedInErrorReport() {
277 static atomic_uint32_t num_calls;
Alexey Samsonov62e27092012-09-17 08:02:19 +0000278 static u32 reporting_thread_tid;
Alexey Samsonov98737922012-08-10 15:13:05 +0000279 if (atomic_fetch_add(&num_calls, 1, memory_order_relaxed) != 0) {
280 // Do not print more than one report, otherwise they will mix up.
281 // Error reporting functions shouldn't return at this situation, as
282 // they are defined as no-return.
Kostya Serebryany283c2962012-08-28 11:34:40 +0000283 Report("AddressSanitizer: while reporting a bug found another one."
Alexey Samsonov98737922012-08-10 15:13:05 +0000284 "Ignoring.\n");
Alexey Samsonov62e27092012-09-17 08:02:19 +0000285 u32 current_tid = asanThreadRegistry().GetCurrentTidOrInvalid();
286 if (current_tid != reporting_thread_tid) {
287 // ASan found two bugs in different threads simultaneously. Sleep
288 // long enough to make sure that the thread which started to print
289 // an error report will finish doing it.
290 SleepForSeconds(Max(100, flags()->sleep_before_dying + 1));
291 }
Alexey Samsonov031633b2012-11-19 11:22:22 +0000292 // If we're still not dead for some reason, use raw Exit() instead of
293 // Die() to bypass any additional checks.
294 Exit(flags()->exitcode);
Alexey Samsonov98737922012-08-10 15:13:05 +0000295 }
Alexey Samsonov86633432012-10-02 14:06:39 +0000296 __asan_on_error();
Alexey Samsonov62e27092012-09-17 08:02:19 +0000297 reporting_thread_tid = asanThreadRegistry().GetCurrentTidOrInvalid();
Kostya Serebryany283c2962012-08-28 11:34:40 +0000298 Printf("===================================================="
Alexey Samsonov62e27092012-09-17 08:02:19 +0000299 "=============\n");
300 if (reporting_thread_tid != kInvalidTid) {
Alexey Samsonov98737922012-08-10 15:13:05 +0000301 // We started reporting an error message. Stop using the fake stack
302 // in case we call an instrumented function from a symbolizer.
Alexey Samsonov62e27092012-09-17 08:02:19 +0000303 AsanThread *curr_thread = asanThreadRegistry().GetCurrent();
304 CHECK(curr_thread);
Alexey Samsonov98737922012-08-10 15:13:05 +0000305 curr_thread->fake_stack().StopUsingFakeStack();
306 }
307 }
308 // Destructor is NORETURN, as functions that report errors are.
309 NORETURN ~ScopedInErrorReport() {
310 // Make sure the current thread is announced.
311 AsanThread *curr_thread = asanThreadRegistry().GetCurrent();
312 if (curr_thread) {
Alexey Samsonov71b42c92012-09-05 07:37:15 +0000313 DescribeThread(curr_thread->summary());
Alexey Samsonov98737922012-08-10 15:13:05 +0000314 }
315 // Print memory stats.
316 __asan_print_accumulated_stats();
317 if (error_report_callback) {
318 error_report_callback(error_message_buffer);
319 }
Kostya Serebryany283c2962012-08-28 11:34:40 +0000320 Report("ABORTING\n");
Alexey Samsonov98737922012-08-10 15:13:05 +0000321 Die();
322 }
323};
324
Alexey Samsonov73545092012-08-09 07:40:58 +0000325void ReportSIGSEGV(uptr pc, uptr sp, uptr bp, uptr addr) {
Alexey Samsonov98737922012-08-10 15:13:05 +0000326 ScopedInErrorReport in_report;
Kostya Serebryany69d8ede2012-10-15 13:04:58 +0000327 Report("ERROR: AddressSanitizer: SEGV on unknown address %p"
Alexey Samsonov73545092012-08-09 07:40:58 +0000328 " (pc %p sp %p bp %p T%d)\n",
329 (void*)addr, (void*)pc, (void*)sp, (void*)bp,
330 asanThreadRegistry().GetCurrentTidOrInvalid());
Kostya Serebryany283c2962012-08-28 11:34:40 +0000331 Printf("AddressSanitizer can not provide additional info.\n");
Alexey Samsonov73545092012-08-09 07:40:58 +0000332 GET_STACK_TRACE_WITH_PC_AND_BP(kStackTraceMax, pc, bp);
Kostya Serebryanycc347222012-08-28 13:49:49 +0000333 PrintStack(&stack);
Alexey Samsonov73545092012-08-09 07:40:58 +0000334}
335
Kostya Serebryanyc3390df2012-08-28 11:54:30 +0000336void ReportDoubleFree(uptr addr, StackTrace *stack) {
Alexey Samsonov98737922012-08-10 15:13:05 +0000337 ScopedInErrorReport in_report;
Kostya Serebryany69d8ede2012-10-15 13:04:58 +0000338 Report("ERROR: AddressSanitizer: attempting double-free on %p:\n", addr);
Kostya Serebryanycc347222012-08-28 13:49:49 +0000339 PrintStack(stack);
Alexey Samsonovf7c1d182012-08-09 08:15:46 +0000340 DescribeHeapAddress(addr, 1);
Alexey Samsonovf7c1d182012-08-09 08:15:46 +0000341}
342
Kostya Serebryanyc3390df2012-08-28 11:54:30 +0000343void ReportFreeNotMalloced(uptr addr, StackTrace *stack) {
Alexey Samsonov98737922012-08-10 15:13:05 +0000344 ScopedInErrorReport in_report;
Kostya Serebryany69d8ede2012-10-15 13:04:58 +0000345 Report("ERROR: AddressSanitizer: attempting free on address "
Alexey Samsonovf7c1d182012-08-09 08:15:46 +0000346 "which was not malloc()-ed: %p\n", addr);
Kostya Serebryanycc347222012-08-28 13:49:49 +0000347 PrintStack(stack);
Alexey Samsonov98737922012-08-10 15:13:05 +0000348 DescribeHeapAddress(addr, 1);
Alexey Samsonovf7c1d182012-08-09 08:15:46 +0000349}
350
Kostya Serebryanyc3390df2012-08-28 11:54:30 +0000351void ReportMallocUsableSizeNotOwned(uptr addr, StackTrace *stack) {
Alexey Samsonov98737922012-08-10 15:13:05 +0000352 ScopedInErrorReport in_report;
Kostya Serebryany69d8ede2012-10-15 13:04:58 +0000353 Report("ERROR: AddressSanitizer: attempting to call "
Alexey Samsonovf7c1d182012-08-09 08:15:46 +0000354 "malloc_usable_size() for pointer which is "
355 "not owned: %p\n", addr);
Kostya Serebryanycc347222012-08-28 13:49:49 +0000356 PrintStack(stack);
Alexey Samsonovf7c1d182012-08-09 08:15:46 +0000357 DescribeHeapAddress(addr, 1);
Alexey Samsonovf7c1d182012-08-09 08:15:46 +0000358}
359
Kostya Serebryanyc3390df2012-08-28 11:54:30 +0000360void ReportAsanGetAllocatedSizeNotOwned(uptr addr, StackTrace *stack) {
Alexey Samsonov98737922012-08-10 15:13:05 +0000361 ScopedInErrorReport in_report;
Kostya Serebryany69d8ede2012-10-15 13:04:58 +0000362 Report("ERROR: AddressSanitizer: attempting to call "
Alexey Samsonovf7c1d182012-08-09 08:15:46 +0000363 "__asan_get_allocated_size() for pointer which is "
364 "not owned: %p\n", addr);
Kostya Serebryanycc347222012-08-28 13:49:49 +0000365 PrintStack(stack);
Alexey Samsonovf7c1d182012-08-09 08:15:46 +0000366 DescribeHeapAddress(addr, 1);
Alexey Samsonovf7c1d182012-08-09 08:15:46 +0000367}
368
Alexey Samsonov487fee72012-08-09 08:32:33 +0000369void ReportStringFunctionMemoryRangesOverlap(
370 const char *function, const char *offset1, uptr length1,
Kostya Serebryanyc3390df2012-08-28 11:54:30 +0000371 const char *offset2, uptr length2, StackTrace *stack) {
Alexey Samsonov98737922012-08-10 15:13:05 +0000372 ScopedInErrorReport in_report;
Kostya Serebryany69d8ede2012-10-15 13:04:58 +0000373 Report("ERROR: AddressSanitizer: %s-param-overlap: "
Alexey Samsonov487fee72012-08-09 08:32:33 +0000374 "memory ranges [%p,%p) and [%p, %p) overlap\n", \
375 function, offset1, offset1 + length1, offset2, offset2 + length2);
Kostya Serebryanycc347222012-08-28 13:49:49 +0000376 PrintStack(stack);
Alexey Samsonov98737922012-08-10 15:13:05 +0000377 DescribeAddress((uptr)offset1, length1);
378 DescribeAddress((uptr)offset2, length2);
Alexey Samsonov487fee72012-08-09 08:32:33 +0000379}
Alexey Samsonovf7c1d182012-08-09 08:15:46 +0000380
Alexey Samsonov663c5012012-08-09 12:15:40 +0000381// ----------------------- Mac-specific reports ----------------- {{{1
382
Alexey Samsonov663c5012012-08-09 12:15:40 +0000383void WarnMacFreeUnallocated(
Kostya Serebryanyc3390df2012-08-28 11:54:30 +0000384 uptr addr, uptr zone_ptr, const char *zone_name, StackTrace *stack) {
Alexey Samsonov98737922012-08-10 15:13:05 +0000385 // Just print a warning here.
Kostya Serebryany283c2962012-08-28 11:34:40 +0000386 Printf("free_common(%p) -- attempting to free unallocated memory.\n"
Alexey Samsonov663c5012012-08-09 12:15:40 +0000387 "AddressSanitizer is ignoring this error on Mac OS now.\n",
388 addr);
389 PrintZoneForPointer(addr, zone_ptr, zone_name);
Kostya Serebryanycc347222012-08-28 13:49:49 +0000390 PrintStack(stack);
Alexey Samsonov98737922012-08-10 15:13:05 +0000391 DescribeHeapAddress(addr, 1);
Alexey Samsonov663c5012012-08-09 12:15:40 +0000392}
393
394void ReportMacMzReallocUnknown(
Kostya Serebryanyc3390df2012-08-28 11:54:30 +0000395 uptr addr, uptr zone_ptr, const char *zone_name, StackTrace *stack) {
Alexey Samsonov98737922012-08-10 15:13:05 +0000396 ScopedInErrorReport in_report;
Kostya Serebryany283c2962012-08-28 11:34:40 +0000397 Printf("mz_realloc(%p) -- attempting to realloc unallocated memory.\n"
Alexey Samsonov663c5012012-08-09 12:15:40 +0000398 "This is an unrecoverable problem, exiting now.\n",
399 addr);
400 PrintZoneForPointer(addr, zone_ptr, zone_name);
Kostya Serebryanycc347222012-08-28 13:49:49 +0000401 PrintStack(stack);
Alexey Samsonov98737922012-08-10 15:13:05 +0000402 DescribeHeapAddress(addr, 1);
Alexey Samsonov663c5012012-08-09 12:15:40 +0000403}
404
405void ReportMacCfReallocUnknown(
Kostya Serebryanyc3390df2012-08-28 11:54:30 +0000406 uptr addr, uptr zone_ptr, const char *zone_name, StackTrace *stack) {
Alexey Samsonov98737922012-08-10 15:13:05 +0000407 ScopedInErrorReport in_report;
Kostya Serebryany283c2962012-08-28 11:34:40 +0000408 Printf("cf_realloc(%p) -- attempting to realloc unallocated memory.\n"
Alexey Samsonov663c5012012-08-09 12:15:40 +0000409 "This is an unrecoverable problem, exiting now.\n",
410 addr);
411 PrintZoneForPointer(addr, zone_ptr, zone_name);
Kostya Serebryanycc347222012-08-28 13:49:49 +0000412 PrintStack(stack);
Alexey Samsonov98737922012-08-10 15:13:05 +0000413 DescribeHeapAddress(addr, 1);
Alexey Samsonovc98570b2012-08-09 10:56:57 +0000414}
415
Alexey Samsonov812ff902012-08-09 11:29:13 +0000416} // namespace __asan
417
418// --------------------------- Interface --------------------- {{{1
419using namespace __asan; // NOLINT
420
421void __asan_report_error(uptr pc, uptr bp, uptr sp,
422 uptr addr, bool is_write, uptr access_size) {
Alexey Samsonov98737922012-08-10 15:13:05 +0000423 ScopedInErrorReport in_report;
Alexey Samsonovc98570b2012-08-09 10:56:57 +0000424
Alexey Samsonov98737922012-08-10 15:13:05 +0000425 // Determine the error type.
Alexey Samsonovc98570b2012-08-09 10:56:57 +0000426 const char *bug_descr = "unknown-crash";
427 if (AddrIsInMem(addr)) {
428 u8 *shadow_addr = (u8*)MemToShadow(addr);
429 // If we are accessing 16 bytes, look at the second shadow byte.
430 if (*shadow_addr == 0 && access_size > SHADOW_GRANULARITY)
431 shadow_addr++;
432 // If we are in the partial right redzone, look at the next shadow byte.
433 if (*shadow_addr > 0 && *shadow_addr < 128)
434 shadow_addr++;
435 switch (*shadow_addr) {
436 case kAsanHeapLeftRedzoneMagic:
437 case kAsanHeapRightRedzoneMagic:
438 bug_descr = "heap-buffer-overflow";
439 break;
440 case kAsanHeapFreeMagic:
441 bug_descr = "heap-use-after-free";
442 break;
443 case kAsanStackLeftRedzoneMagic:
444 bug_descr = "stack-buffer-underflow";
445 break;
Kostya Serebryany3945c582012-08-21 14:10:25 +0000446 case kAsanInitializationOrderMagic:
447 bug_descr = "initialization-order-fiasco";
448 break;
Alexey Samsonovc98570b2012-08-09 10:56:57 +0000449 case kAsanStackMidRedzoneMagic:
450 case kAsanStackRightRedzoneMagic:
451 case kAsanStackPartialRedzoneMagic:
452 bug_descr = "stack-buffer-overflow";
453 break;
454 case kAsanStackAfterReturnMagic:
455 bug_descr = "stack-use-after-return";
456 break;
457 case kAsanUserPoisonedMemoryMagic:
458 bug_descr = "use-after-poison";
459 break;
460 case kAsanGlobalRedzoneMagic:
461 bug_descr = "global-buffer-overflow";
462 break;
463 }
464 }
465
Kostya Serebryany69d8ede2012-10-15 13:04:58 +0000466 Report("ERROR: AddressSanitizer: %s on address "
Alexey Samsonovc98570b2012-08-09 10:56:57 +0000467 "%p at pc 0x%zx bp 0x%zx sp 0x%zx\n",
468 bug_descr, (void*)addr, pc, bp, sp);
469
Alexey Samsonov98737922012-08-10 15:13:05 +0000470 u32 curr_tid = asanThreadRegistry().GetCurrentTidOrInvalid();
Kostya Serebryany283c2962012-08-28 11:34:40 +0000471 Printf("%s of size %zu at %p thread T%d\n",
Alexey Samsonovc98570b2012-08-09 10:56:57 +0000472 access_size ? (is_write ? "WRITE" : "READ") : "ACCESS",
473 access_size, (void*)addr, curr_tid);
474
Alexey Samsonovc98570b2012-08-09 10:56:57 +0000475 GET_STACK_TRACE_WITH_PC_AND_BP(kStackTraceMax, pc, bp);
Kostya Serebryanycc347222012-08-28 13:49:49 +0000476 PrintStack(&stack);
Alexey Samsonovc98570b2012-08-09 10:56:57 +0000477
478 DescribeAddress(addr, access_size);
479
Alexey Samsonov98737922012-08-10 15:13:05 +0000480 PrintShadowMemoryForAddress(addr);
Alexey Samsonovc98570b2012-08-09 10:56:57 +0000481}
482
Alexey Samsonovc98570b2012-08-09 10:56:57 +0000483void NOINLINE __asan_set_error_report_callback(void (*callback)(const char*)) {
484 error_report_callback = callback;
485 if (callback) {
486 error_message_buffer_size = 1 << 16;
487 error_message_buffer =
488 (char*)MmapOrDie(error_message_buffer_size, __FUNCTION__);
489 error_message_buffer_pos = 0;
490 }
491}
Alexey Samsonovf657a192012-08-13 11:23:40 +0000492
Alexey Samsonov86633432012-10-02 14:06:39 +0000493// Provide default implementation of __asan_on_error that does nothing
494// and may be overriden by user.
495SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE NOINLINE
496void __asan_on_error() {}