Alexey Samsonov | 7354509 | 2012-08-09 07:40:58 +0000 | [diff] [blame] | 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 | //===----------------------------------------------------------------------===// |
Alexey Samsonov | 9873792 | 2012-08-10 15:13:05 +0000 | [diff] [blame] | 14 | #include "asan_flags.h" |
Alexey Samsonov | 7354509 | 2012-08-09 07:40:58 +0000 | [diff] [blame] | 15 | #include "asan_internal.h" |
Alexey Samsonov | e218beb | 2012-08-09 09:06:52 +0000 | [diff] [blame] | 16 | #include "asan_mapping.h" |
Alexey Samsonov | 7354509 | 2012-08-09 07:40:58 +0000 | [diff] [blame] | 17 | #include "asan_report.h" |
| 18 | #include "asan_stack.h" |
Alexey Samsonov | e4bfca2 | 2012-08-09 09:27:24 +0000 | [diff] [blame] | 19 | #include "asan_thread.h" |
Alexey Samsonov | 7354509 | 2012-08-09 07:40:58 +0000 | [diff] [blame] | 20 | #include "asan_thread_registry.h" |
| 21 | |
| 22 | namespace __asan { |
| 23 | |
Alexey Samsonov | f657a19 | 2012-08-13 11:23:40 +0000 | [diff] [blame] | 24 | // -------------------- User-specified callbacks ----------------- {{{1 |
Alexey Samsonov | c98570b | 2012-08-09 10:56:57 +0000 | [diff] [blame] | 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 | |
Alexey Samsonov | 9873792 | 2012-08-10 15:13:05 +0000 | [diff] [blame] | 43 | // ---------------------- Helper functions ----------------------- {{{1 |
| 44 | |
| 45 | static void PrintBytes(const char *before, uptr *a) { |
| 46 | u8 *bytes = (u8*)a; |
Kostya Serebryany | 5af39e5 | 2012-11-21 12:38:58 +0000 | [diff] [blame] | 47 | uptr byte_num = (SANITIZER_WORDSIZE) / 8; |
Kostya Serebryany | 283c296 | 2012-08-28 11:34:40 +0000 | [diff] [blame] | 48 | Printf("%s%p:", before, (void*)a); |
Alexey Samsonov | 9873792 | 2012-08-10 15:13:05 +0000 | [diff] [blame] | 49 | for (uptr i = 0; i < byte_num; i++) { |
Kostya Serebryany | 283c296 | 2012-08-28 11:34:40 +0000 | [diff] [blame] | 50 | Printf(" %x%x", bytes[i] >> 4, bytes[i] & 15); |
Alexey Samsonov | 9873792 | 2012-08-10 15:13:05 +0000 | [diff] [blame] | 51 | } |
Kostya Serebryany | 283c296 | 2012-08-28 11:34:40 +0000 | [diff] [blame] | 52 | Printf("\n"); |
Alexey Samsonov | 9873792 | 2012-08-10 15:13:05 +0000 | [diff] [blame] | 53 | } |
| 54 | |
| 55 | static void PrintShadowMemoryForAddress(uptr addr) { |
| 56 | if (!AddrIsInMem(addr)) |
| 57 | return; |
| 58 | uptr shadow_addr = MemToShadow(addr); |
Kostya Serebryany | 283c296 | 2012-08-28 11:34:40 +0000 | [diff] [blame] | 59 | Printf("Shadow byte and word:\n"); |
| 60 | Printf(" %p: %x\n", (void*)shadow_addr, *(unsigned char*)shadow_addr); |
Alexey Samsonov | 9873792 | 2012-08-10 15:13:05 +0000 | [diff] [blame] | 61 | uptr aligned_shadow = shadow_addr & ~(kWordSize - 1); |
| 62 | PrintBytes(" ", (uptr*)(aligned_shadow)); |
Kostya Serebryany | 283c296 | 2012-08-28 11:34:40 +0000 | [diff] [blame] | 63 | Printf("More shadow bytes:\n"); |
Alexey Samsonov | 9873792 | 2012-08-10 15:13:05 +0000 | [diff] [blame] | 64 | for (int i = -4; i <= 4; i++) { |
| 65 | const char *prefix = (i == 0) ? "=>" : " "; |
| 66 | PrintBytes(prefix, (uptr*)(aligned_shadow + i * kWordSize)); |
| 67 | } |
| 68 | } |
| 69 | |
| 70 | static void PrintZoneForPointer(uptr ptr, uptr zone_ptr, |
| 71 | const char *zone_name) { |
| 72 | if (zone_ptr) { |
| 73 | if (zone_name) { |
Kostya Serebryany | 283c296 | 2012-08-28 11:34:40 +0000 | [diff] [blame] | 74 | Printf("malloc_zone_from_ptr(%p) = %p, which is %s\n", |
Alexey Samsonov | 9873792 | 2012-08-10 15:13:05 +0000 | [diff] [blame] | 75 | ptr, zone_ptr, zone_name); |
| 76 | } else { |
Kostya Serebryany | 283c296 | 2012-08-28 11:34:40 +0000 | [diff] [blame] | 77 | Printf("malloc_zone_from_ptr(%p) = %p, which doesn't have a name\n", |
Alexey Samsonov | 9873792 | 2012-08-10 15:13:05 +0000 | [diff] [blame] | 78 | ptr, zone_ptr); |
| 79 | } |
| 80 | } else { |
Kostya Serebryany | 283c296 | 2012-08-28 11:34:40 +0000 | [diff] [blame] | 81 | Printf("malloc_zone_from_ptr(%p) = 0\n", ptr); |
Alexey Samsonov | 9873792 | 2012-08-10 15:13:05 +0000 | [diff] [blame] | 82 | } |
| 83 | } |
| 84 | |
Alexey Samsonov | e218beb | 2012-08-09 09:06:52 +0000 | [diff] [blame] | 85 | // ---------------------- Address Descriptions ------------------- {{{1 |
| 86 | |
Alexey Samsonov | e4bfca2 | 2012-08-09 09:27:24 +0000 | [diff] [blame] | 87 | static bool IsASCII(unsigned char c) { |
Alexey Samsonov | 9873792 | 2012-08-10 15:13:05 +0000 | [diff] [blame] | 88 | return /*0x00 <= c &&*/ c <= 0x7F; |
Alexey Samsonov | e4bfca2 | 2012-08-09 09:27:24 +0000 | [diff] [blame] | 89 | } |
| 90 | |
| 91 | // Check if the global is a zero-terminated ASCII string. If so, print it. |
| 92 | static 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 Serebryany | 283c296 | 2012-08-28 11:34:40 +0000 | [diff] [blame] | 97 | Printf(" '%s' is ascii string '%s'\n", g.name, (char*)g.beg); |
Alexey Samsonov | e4bfca2 | 2012-08-09 09:27:24 +0000 | [diff] [blame] | 98 | } |
| 99 | |
| 100 | bool 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 Serebryany | 283c296 | 2012-08-28 11:34:40 +0000 | [diff] [blame] | 103 | Printf("%p is located ", (void*)addr); |
Alexey Samsonov | e4bfca2 | 2012-08-09 09:27:24 +0000 | [diff] [blame] | 104 | if (addr < g.beg) { |
Kostya Serebryany | 283c296 | 2012-08-28 11:34:40 +0000 | [diff] [blame] | 105 | Printf("%zd bytes to the left", g.beg - addr); |
Alexey Samsonov | e4bfca2 | 2012-08-09 09:27:24 +0000 | [diff] [blame] | 106 | } else if (addr >= g.beg + g.size) { |
Kostya Serebryany | 283c296 | 2012-08-28 11:34:40 +0000 | [diff] [blame] | 107 | Printf("%zd bytes to the right", addr - (g.beg + g.size)); |
Alexey Samsonov | e4bfca2 | 2012-08-09 09:27:24 +0000 | [diff] [blame] | 108 | } else { |
Kostya Serebryany | 283c296 | 2012-08-28 11:34:40 +0000 | [diff] [blame] | 109 | Printf("%zd bytes inside", addr - g.beg); // Can it happen? |
Alexey Samsonov | e4bfca2 | 2012-08-09 09:27:24 +0000 | [diff] [blame] | 110 | } |
Kostya Serebryany | 283c296 | 2012-08-28 11:34:40 +0000 | [diff] [blame] | 111 | Printf(" of global variable '%s' (0x%zx) of size %zu\n", |
Alexey Samsonov | e4bfca2 | 2012-08-09 09:27:24 +0000 | [diff] [blame] | 112 | g.name, g.beg, g.size); |
| 113 | PrintGlobalNameIfASCII(g); |
| 114 | return true; |
| 115 | } |
| 116 | |
Alexey Samsonov | e218beb | 2012-08-09 09:06:52 +0000 | [diff] [blame] | 117 | bool 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 Serebryany | 283c296 | 2012-08-28 11:34:40 +0000 | [diff] [blame] | 123 | Printf(kAddrInShadowReport, addr, "shadow gap area"); |
Alexey Samsonov | e218beb | 2012-08-09 09:06:52 +0000 | [diff] [blame] | 124 | return true; |
| 125 | } |
| 126 | if (AddrIsInHighShadow(addr)) { |
Kostya Serebryany | 283c296 | 2012-08-28 11:34:40 +0000 | [diff] [blame] | 127 | Printf(kAddrInShadowReport, addr, "high shadow area"); |
Alexey Samsonov | e218beb | 2012-08-09 09:06:52 +0000 | [diff] [blame] | 128 | return true; |
| 129 | } |
| 130 | if (AddrIsInLowShadow(addr)) { |
Kostya Serebryany | 283c296 | 2012-08-28 11:34:40 +0000 | [diff] [blame] | 131 | Printf(kAddrInShadowReport, addr, "low shadow area"); |
Alexey Samsonov | e218beb | 2012-08-09 09:06:52 +0000 | [diff] [blame] | 132 | return true; |
| 133 | } |
| 134 | CHECK(0 && "Address is not in memory and not in shadow?"); |
| 135 | return false; |
| 136 | } |
| 137 | |
| 138 | bool 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 Serebryany | 283c296 | 2012-08-28 11:34:40 +0000 | [diff] [blame] | 156 | Printf("Address %p is located at offset %zu " |
Alexey Samsonov | e218beb | 2012-08-09 09:06:52 +0000 | [diff] [blame] | 157 | "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 Serebryany | 283c296 | 2012-08-28 11:34:40 +0000 | [diff] [blame] | 163 | Printf(" This frame has %zu object(s):\n", n_objects); |
Alexey Samsonov | e218beb | 2012-08-09 09:06:52 +0000 | [diff] [blame] | 164 | // 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 Serebryany | 283c296 | 2012-08-28 11:34:40 +0000 | [diff] [blame] | 172 | Printf("AddressSanitizer can't parse the stack frame " |
Alexey Samsonov | e218beb | 2012-08-09 09:06:52 +0000 | [diff] [blame] | 173 | "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 Serebryany | 283c296 | 2012-08-28 11:34:40 +0000 | [diff] [blame] | 180 | Printf(" [%zu, %zu) '%s'\n", beg, beg + size, buf); |
Alexey Samsonov | e218beb | 2012-08-09 09:06:52 +0000 | [diff] [blame] | 181 | } |
Kostya Serebryany | 283c296 | 2012-08-28 11:34:40 +0000 | [diff] [blame] | 182 | Printf("HINT: this may be a false positive if your program uses " |
Alexey Samsonov | 0870028 | 2012-11-23 09:46:34 +0000 | [diff] [blame^] | 183 | "some custom stack unwind mechanism or swapcontext\n" |
Alexey Samsonov | e218beb | 2012-08-09 09:06:52 +0000 | [diff] [blame] | 184 | " (longjmp and C++ exceptions *are* supported)\n"); |
Alexey Samsonov | 71b42c9 | 2012-09-05 07:37:15 +0000 | [diff] [blame] | 185 | DescribeThread(t->summary()); |
Alexey Samsonov | e218beb | 2012-08-09 09:06:52 +0000 | [diff] [blame] | 186 | return true; |
| 187 | } |
| 188 | |
Alexey Samsonov | 5c153fa | 2012-09-18 07:38:10 +0000 | [diff] [blame] | 189 | static 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 | |
| 206 | void 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 Samsonov | e218beb | 2012-08-09 09:06:52 +0000 | [diff] [blame] | 237 | void 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 Samsonov | 71b42c9 | 2012-09-05 07:37:15 +0000 | [diff] [blame] | 250 | // ------------------- Thread description -------------------- {{{1 |
| 251 | |
| 252 | void 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 Samsonov | e218beb | 2012-08-09 09:06:52 +0000 | [diff] [blame] | 270 | // -------------------- Different kinds of reports ----------------- {{{1 |
| 271 | |
Alexey Samsonov | 9873792 | 2012-08-10 15:13:05 +0000 | [diff] [blame] | 272 | // Use ScopedInErrorReport to run common actions just before and |
| 273 | // immediately after printing error report. |
| 274 | class ScopedInErrorReport { |
| 275 | public: |
| 276 | ScopedInErrorReport() { |
| 277 | static atomic_uint32_t num_calls; |
Alexey Samsonov | 62e2709 | 2012-09-17 08:02:19 +0000 | [diff] [blame] | 278 | static u32 reporting_thread_tid; |
Alexey Samsonov | 9873792 | 2012-08-10 15:13:05 +0000 | [diff] [blame] | 279 | 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 Serebryany | 283c296 | 2012-08-28 11:34:40 +0000 | [diff] [blame] | 283 | Report("AddressSanitizer: while reporting a bug found another one." |
Alexey Samsonov | 9873792 | 2012-08-10 15:13:05 +0000 | [diff] [blame] | 284 | "Ignoring.\n"); |
Alexey Samsonov | 62e2709 | 2012-09-17 08:02:19 +0000 | [diff] [blame] | 285 | 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 Samsonov | 031633b | 2012-11-19 11:22:22 +0000 | [diff] [blame] | 292 | // 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 Samsonov | 9873792 | 2012-08-10 15:13:05 +0000 | [diff] [blame] | 295 | } |
Alexey Samsonov | 8663343 | 2012-10-02 14:06:39 +0000 | [diff] [blame] | 296 | __asan_on_error(); |
Alexey Samsonov | 62e2709 | 2012-09-17 08:02:19 +0000 | [diff] [blame] | 297 | reporting_thread_tid = asanThreadRegistry().GetCurrentTidOrInvalid(); |
Kostya Serebryany | 283c296 | 2012-08-28 11:34:40 +0000 | [diff] [blame] | 298 | Printf("====================================================" |
Alexey Samsonov | 62e2709 | 2012-09-17 08:02:19 +0000 | [diff] [blame] | 299 | "=============\n"); |
| 300 | if (reporting_thread_tid != kInvalidTid) { |
Alexey Samsonov | 9873792 | 2012-08-10 15:13:05 +0000 | [diff] [blame] | 301 | // We started reporting an error message. Stop using the fake stack |
| 302 | // in case we call an instrumented function from a symbolizer. |
Alexey Samsonov | 62e2709 | 2012-09-17 08:02:19 +0000 | [diff] [blame] | 303 | AsanThread *curr_thread = asanThreadRegistry().GetCurrent(); |
| 304 | CHECK(curr_thread); |
Alexey Samsonov | 9873792 | 2012-08-10 15:13:05 +0000 | [diff] [blame] | 305 | 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 Samsonov | 71b42c9 | 2012-09-05 07:37:15 +0000 | [diff] [blame] | 313 | DescribeThread(curr_thread->summary()); |
Alexey Samsonov | 9873792 | 2012-08-10 15:13:05 +0000 | [diff] [blame] | 314 | } |
| 315 | // Print memory stats. |
| 316 | __asan_print_accumulated_stats(); |
| 317 | if (error_report_callback) { |
| 318 | error_report_callback(error_message_buffer); |
| 319 | } |
Kostya Serebryany | 283c296 | 2012-08-28 11:34:40 +0000 | [diff] [blame] | 320 | Report("ABORTING\n"); |
Alexey Samsonov | 9873792 | 2012-08-10 15:13:05 +0000 | [diff] [blame] | 321 | Die(); |
| 322 | } |
| 323 | }; |
| 324 | |
Alexey Samsonov | 7354509 | 2012-08-09 07:40:58 +0000 | [diff] [blame] | 325 | void ReportSIGSEGV(uptr pc, uptr sp, uptr bp, uptr addr) { |
Alexey Samsonov | 9873792 | 2012-08-10 15:13:05 +0000 | [diff] [blame] | 326 | ScopedInErrorReport in_report; |
Kostya Serebryany | 69d8ede | 2012-10-15 13:04:58 +0000 | [diff] [blame] | 327 | Report("ERROR: AddressSanitizer: SEGV on unknown address %p" |
Alexey Samsonov | 7354509 | 2012-08-09 07:40:58 +0000 | [diff] [blame] | 328 | " (pc %p sp %p bp %p T%d)\n", |
| 329 | (void*)addr, (void*)pc, (void*)sp, (void*)bp, |
| 330 | asanThreadRegistry().GetCurrentTidOrInvalid()); |
Kostya Serebryany | 283c296 | 2012-08-28 11:34:40 +0000 | [diff] [blame] | 331 | Printf("AddressSanitizer can not provide additional info.\n"); |
Alexey Samsonov | 7354509 | 2012-08-09 07:40:58 +0000 | [diff] [blame] | 332 | GET_STACK_TRACE_WITH_PC_AND_BP(kStackTraceMax, pc, bp); |
Kostya Serebryany | cc34722 | 2012-08-28 13:49:49 +0000 | [diff] [blame] | 333 | PrintStack(&stack); |
Alexey Samsonov | 7354509 | 2012-08-09 07:40:58 +0000 | [diff] [blame] | 334 | } |
| 335 | |
Kostya Serebryany | c3390df | 2012-08-28 11:54:30 +0000 | [diff] [blame] | 336 | void ReportDoubleFree(uptr addr, StackTrace *stack) { |
Alexey Samsonov | 9873792 | 2012-08-10 15:13:05 +0000 | [diff] [blame] | 337 | ScopedInErrorReport in_report; |
Kostya Serebryany | 69d8ede | 2012-10-15 13:04:58 +0000 | [diff] [blame] | 338 | Report("ERROR: AddressSanitizer: attempting double-free on %p:\n", addr); |
Kostya Serebryany | cc34722 | 2012-08-28 13:49:49 +0000 | [diff] [blame] | 339 | PrintStack(stack); |
Alexey Samsonov | f7c1d18 | 2012-08-09 08:15:46 +0000 | [diff] [blame] | 340 | DescribeHeapAddress(addr, 1); |
Alexey Samsonov | f7c1d18 | 2012-08-09 08:15:46 +0000 | [diff] [blame] | 341 | } |
| 342 | |
Kostya Serebryany | c3390df | 2012-08-28 11:54:30 +0000 | [diff] [blame] | 343 | void ReportFreeNotMalloced(uptr addr, StackTrace *stack) { |
Alexey Samsonov | 9873792 | 2012-08-10 15:13:05 +0000 | [diff] [blame] | 344 | ScopedInErrorReport in_report; |
Kostya Serebryany | 69d8ede | 2012-10-15 13:04:58 +0000 | [diff] [blame] | 345 | Report("ERROR: AddressSanitizer: attempting free on address " |
Alexey Samsonov | f7c1d18 | 2012-08-09 08:15:46 +0000 | [diff] [blame] | 346 | "which was not malloc()-ed: %p\n", addr); |
Kostya Serebryany | cc34722 | 2012-08-28 13:49:49 +0000 | [diff] [blame] | 347 | PrintStack(stack); |
Alexey Samsonov | 9873792 | 2012-08-10 15:13:05 +0000 | [diff] [blame] | 348 | DescribeHeapAddress(addr, 1); |
Alexey Samsonov | f7c1d18 | 2012-08-09 08:15:46 +0000 | [diff] [blame] | 349 | } |
| 350 | |
Kostya Serebryany | c3390df | 2012-08-28 11:54:30 +0000 | [diff] [blame] | 351 | void ReportMallocUsableSizeNotOwned(uptr addr, StackTrace *stack) { |
Alexey Samsonov | 9873792 | 2012-08-10 15:13:05 +0000 | [diff] [blame] | 352 | ScopedInErrorReport in_report; |
Kostya Serebryany | 69d8ede | 2012-10-15 13:04:58 +0000 | [diff] [blame] | 353 | Report("ERROR: AddressSanitizer: attempting to call " |
Alexey Samsonov | f7c1d18 | 2012-08-09 08:15:46 +0000 | [diff] [blame] | 354 | "malloc_usable_size() for pointer which is " |
| 355 | "not owned: %p\n", addr); |
Kostya Serebryany | cc34722 | 2012-08-28 13:49:49 +0000 | [diff] [blame] | 356 | PrintStack(stack); |
Alexey Samsonov | f7c1d18 | 2012-08-09 08:15:46 +0000 | [diff] [blame] | 357 | DescribeHeapAddress(addr, 1); |
Alexey Samsonov | f7c1d18 | 2012-08-09 08:15:46 +0000 | [diff] [blame] | 358 | } |
| 359 | |
Kostya Serebryany | c3390df | 2012-08-28 11:54:30 +0000 | [diff] [blame] | 360 | void ReportAsanGetAllocatedSizeNotOwned(uptr addr, StackTrace *stack) { |
Alexey Samsonov | 9873792 | 2012-08-10 15:13:05 +0000 | [diff] [blame] | 361 | ScopedInErrorReport in_report; |
Kostya Serebryany | 69d8ede | 2012-10-15 13:04:58 +0000 | [diff] [blame] | 362 | Report("ERROR: AddressSanitizer: attempting to call " |
Alexey Samsonov | f7c1d18 | 2012-08-09 08:15:46 +0000 | [diff] [blame] | 363 | "__asan_get_allocated_size() for pointer which is " |
| 364 | "not owned: %p\n", addr); |
Kostya Serebryany | cc34722 | 2012-08-28 13:49:49 +0000 | [diff] [blame] | 365 | PrintStack(stack); |
Alexey Samsonov | f7c1d18 | 2012-08-09 08:15:46 +0000 | [diff] [blame] | 366 | DescribeHeapAddress(addr, 1); |
Alexey Samsonov | f7c1d18 | 2012-08-09 08:15:46 +0000 | [diff] [blame] | 367 | } |
| 368 | |
Alexey Samsonov | 487fee7 | 2012-08-09 08:32:33 +0000 | [diff] [blame] | 369 | void ReportStringFunctionMemoryRangesOverlap( |
| 370 | const char *function, const char *offset1, uptr length1, |
Kostya Serebryany | c3390df | 2012-08-28 11:54:30 +0000 | [diff] [blame] | 371 | const char *offset2, uptr length2, StackTrace *stack) { |
Alexey Samsonov | 9873792 | 2012-08-10 15:13:05 +0000 | [diff] [blame] | 372 | ScopedInErrorReport in_report; |
Kostya Serebryany | 69d8ede | 2012-10-15 13:04:58 +0000 | [diff] [blame] | 373 | Report("ERROR: AddressSanitizer: %s-param-overlap: " |
Alexey Samsonov | 487fee7 | 2012-08-09 08:32:33 +0000 | [diff] [blame] | 374 | "memory ranges [%p,%p) and [%p, %p) overlap\n", \ |
| 375 | function, offset1, offset1 + length1, offset2, offset2 + length2); |
Kostya Serebryany | cc34722 | 2012-08-28 13:49:49 +0000 | [diff] [blame] | 376 | PrintStack(stack); |
Alexey Samsonov | 9873792 | 2012-08-10 15:13:05 +0000 | [diff] [blame] | 377 | DescribeAddress((uptr)offset1, length1); |
| 378 | DescribeAddress((uptr)offset2, length2); |
Alexey Samsonov | 487fee7 | 2012-08-09 08:32:33 +0000 | [diff] [blame] | 379 | } |
Alexey Samsonov | f7c1d18 | 2012-08-09 08:15:46 +0000 | [diff] [blame] | 380 | |
Alexey Samsonov | 663c501 | 2012-08-09 12:15:40 +0000 | [diff] [blame] | 381 | // ----------------------- Mac-specific reports ----------------- {{{1 |
| 382 | |
Alexey Samsonov | 663c501 | 2012-08-09 12:15:40 +0000 | [diff] [blame] | 383 | void WarnMacFreeUnallocated( |
Kostya Serebryany | c3390df | 2012-08-28 11:54:30 +0000 | [diff] [blame] | 384 | uptr addr, uptr zone_ptr, const char *zone_name, StackTrace *stack) { |
Alexey Samsonov | 9873792 | 2012-08-10 15:13:05 +0000 | [diff] [blame] | 385 | // Just print a warning here. |
Kostya Serebryany | 283c296 | 2012-08-28 11:34:40 +0000 | [diff] [blame] | 386 | Printf("free_common(%p) -- attempting to free unallocated memory.\n" |
Alexey Samsonov | 663c501 | 2012-08-09 12:15:40 +0000 | [diff] [blame] | 387 | "AddressSanitizer is ignoring this error on Mac OS now.\n", |
| 388 | addr); |
| 389 | PrintZoneForPointer(addr, zone_ptr, zone_name); |
Kostya Serebryany | cc34722 | 2012-08-28 13:49:49 +0000 | [diff] [blame] | 390 | PrintStack(stack); |
Alexey Samsonov | 9873792 | 2012-08-10 15:13:05 +0000 | [diff] [blame] | 391 | DescribeHeapAddress(addr, 1); |
Alexey Samsonov | 663c501 | 2012-08-09 12:15:40 +0000 | [diff] [blame] | 392 | } |
| 393 | |
| 394 | void ReportMacMzReallocUnknown( |
Kostya Serebryany | c3390df | 2012-08-28 11:54:30 +0000 | [diff] [blame] | 395 | uptr addr, uptr zone_ptr, const char *zone_name, StackTrace *stack) { |
Alexey Samsonov | 9873792 | 2012-08-10 15:13:05 +0000 | [diff] [blame] | 396 | ScopedInErrorReport in_report; |
Kostya Serebryany | 283c296 | 2012-08-28 11:34:40 +0000 | [diff] [blame] | 397 | Printf("mz_realloc(%p) -- attempting to realloc unallocated memory.\n" |
Alexey Samsonov | 663c501 | 2012-08-09 12:15:40 +0000 | [diff] [blame] | 398 | "This is an unrecoverable problem, exiting now.\n", |
| 399 | addr); |
| 400 | PrintZoneForPointer(addr, zone_ptr, zone_name); |
Kostya Serebryany | cc34722 | 2012-08-28 13:49:49 +0000 | [diff] [blame] | 401 | PrintStack(stack); |
Alexey Samsonov | 9873792 | 2012-08-10 15:13:05 +0000 | [diff] [blame] | 402 | DescribeHeapAddress(addr, 1); |
Alexey Samsonov | 663c501 | 2012-08-09 12:15:40 +0000 | [diff] [blame] | 403 | } |
| 404 | |
| 405 | void ReportMacCfReallocUnknown( |
Kostya Serebryany | c3390df | 2012-08-28 11:54:30 +0000 | [diff] [blame] | 406 | uptr addr, uptr zone_ptr, const char *zone_name, StackTrace *stack) { |
Alexey Samsonov | 9873792 | 2012-08-10 15:13:05 +0000 | [diff] [blame] | 407 | ScopedInErrorReport in_report; |
Kostya Serebryany | 283c296 | 2012-08-28 11:34:40 +0000 | [diff] [blame] | 408 | Printf("cf_realloc(%p) -- attempting to realloc unallocated memory.\n" |
Alexey Samsonov | 663c501 | 2012-08-09 12:15:40 +0000 | [diff] [blame] | 409 | "This is an unrecoverable problem, exiting now.\n", |
| 410 | addr); |
| 411 | PrintZoneForPointer(addr, zone_ptr, zone_name); |
Kostya Serebryany | cc34722 | 2012-08-28 13:49:49 +0000 | [diff] [blame] | 412 | PrintStack(stack); |
Alexey Samsonov | 9873792 | 2012-08-10 15:13:05 +0000 | [diff] [blame] | 413 | DescribeHeapAddress(addr, 1); |
Alexey Samsonov | c98570b | 2012-08-09 10:56:57 +0000 | [diff] [blame] | 414 | } |
| 415 | |
Alexey Samsonov | 812ff90 | 2012-08-09 11:29:13 +0000 | [diff] [blame] | 416 | } // namespace __asan |
| 417 | |
| 418 | // --------------------------- Interface --------------------- {{{1 |
| 419 | using namespace __asan; // NOLINT |
| 420 | |
| 421 | void __asan_report_error(uptr pc, uptr bp, uptr sp, |
| 422 | uptr addr, bool is_write, uptr access_size) { |
Alexey Samsonov | 9873792 | 2012-08-10 15:13:05 +0000 | [diff] [blame] | 423 | ScopedInErrorReport in_report; |
Alexey Samsonov | c98570b | 2012-08-09 10:56:57 +0000 | [diff] [blame] | 424 | |
Alexey Samsonov | 9873792 | 2012-08-10 15:13:05 +0000 | [diff] [blame] | 425 | // Determine the error type. |
Alexey Samsonov | c98570b | 2012-08-09 10:56:57 +0000 | [diff] [blame] | 426 | 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 Serebryany | 3945c58 | 2012-08-21 14:10:25 +0000 | [diff] [blame] | 446 | case kAsanInitializationOrderMagic: |
| 447 | bug_descr = "initialization-order-fiasco"; |
| 448 | break; |
Alexey Samsonov | c98570b | 2012-08-09 10:56:57 +0000 | [diff] [blame] | 449 | 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 Serebryany | 69d8ede | 2012-10-15 13:04:58 +0000 | [diff] [blame] | 466 | Report("ERROR: AddressSanitizer: %s on address " |
Alexey Samsonov | c98570b | 2012-08-09 10:56:57 +0000 | [diff] [blame] | 467 | "%p at pc 0x%zx bp 0x%zx sp 0x%zx\n", |
| 468 | bug_descr, (void*)addr, pc, bp, sp); |
| 469 | |
Alexey Samsonov | 9873792 | 2012-08-10 15:13:05 +0000 | [diff] [blame] | 470 | u32 curr_tid = asanThreadRegistry().GetCurrentTidOrInvalid(); |
Kostya Serebryany | 283c296 | 2012-08-28 11:34:40 +0000 | [diff] [blame] | 471 | Printf("%s of size %zu at %p thread T%d\n", |
Alexey Samsonov | c98570b | 2012-08-09 10:56:57 +0000 | [diff] [blame] | 472 | access_size ? (is_write ? "WRITE" : "READ") : "ACCESS", |
| 473 | access_size, (void*)addr, curr_tid); |
| 474 | |
Alexey Samsonov | c98570b | 2012-08-09 10:56:57 +0000 | [diff] [blame] | 475 | GET_STACK_TRACE_WITH_PC_AND_BP(kStackTraceMax, pc, bp); |
Kostya Serebryany | cc34722 | 2012-08-28 13:49:49 +0000 | [diff] [blame] | 476 | PrintStack(&stack); |
Alexey Samsonov | c98570b | 2012-08-09 10:56:57 +0000 | [diff] [blame] | 477 | |
| 478 | DescribeAddress(addr, access_size); |
| 479 | |
Alexey Samsonov | 9873792 | 2012-08-10 15:13:05 +0000 | [diff] [blame] | 480 | PrintShadowMemoryForAddress(addr); |
Alexey Samsonov | c98570b | 2012-08-09 10:56:57 +0000 | [diff] [blame] | 481 | } |
| 482 | |
Alexey Samsonov | c98570b | 2012-08-09 10:56:57 +0000 | [diff] [blame] | 483 | void 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 Samsonov | f657a19 | 2012-08-13 11:23:40 +0000 | [diff] [blame] | 492 | |
Alexey Samsonov | 8663343 | 2012-10-02 14:06:39 +0000 | [diff] [blame] | 493 | // Provide default implementation of __asan_on_error that does nothing |
| 494 | // and may be overriden by user. |
| 495 | SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE NOINLINE |
| 496 | void __asan_on_error() {} |