1 | //===-- asan_errors.cpp -----------------------------------------*- C++ -*-===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This file is a part of AddressSanitizer, an address sanity checker. |
10 | // |
11 | // ASan implementation for error structures. |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #include "asan_errors.h" |
15 | #include "asan_descriptions.h" |
16 | #include "asan_mapping.h" |
17 | #include "asan_report.h" |
18 | #include "asan_stack.h" |
19 | #include "sanitizer_common/sanitizer_stackdepot.h" |
20 | |
21 | namespace __asan { |
22 | |
23 | static void OnStackUnwind(const SignalContext &sig, |
24 | const void *callback_context, |
25 | BufferedStackTrace *stack) { |
26 | bool fast = common_flags()->fast_unwind_on_fatal; |
27 | #if SANITIZER_FREEBSD || SANITIZER_NETBSD |
28 | // On FreeBSD the slow unwinding that leverages _Unwind_Backtrace() |
29 | // yields the call stack of the signal's handler and not of the code |
30 | // that raised the signal (as it does on Linux). |
31 | fast = true; |
32 | #endif |
33 | // Tests and maybe some users expect that scariness is going to be printed |
34 | // just before the stack. As only asan has scariness score we have no |
35 | // corresponding code in the sanitizer_common and we use this callback to |
36 | // print it. |
37 | static_cast<const ScarinessScoreBase *>(callback_context)->Print(); |
38 | stack->Unwind(pc: StackTrace::GetNextInstructionPc(pc: sig.pc), bp: sig.bp, context: sig.context, |
39 | request_fast: fast); |
40 | } |
41 | |
42 | void ErrorDeadlySignal::Print() { |
43 | ReportDeadlySignal(sig: signal, tid, unwind: &OnStackUnwind, unwind_context: &scariness); |
44 | } |
45 | |
46 | void ErrorDoubleFree::Print() { |
47 | Decorator d; |
48 | Printf(format: "%s" , d.Error()); |
49 | Report(format: "ERROR: AddressSanitizer: attempting %s on %p in thread %s:\n" , |
50 | scariness.GetDescription(), (void *)addr_description.addr, |
51 | AsanThreadIdAndName(tid).c_str()); |
52 | Printf(format: "%s" , d.Default()); |
53 | scariness.Print(); |
54 | GET_STACK_TRACE_FATAL(second_free_stack->trace[0], |
55 | second_free_stack->top_frame_bp); |
56 | stack.Print(); |
57 | addr_description.Print(); |
58 | ReportErrorSummary(error_type: scariness.GetDescription(), trace: &stack); |
59 | } |
60 | |
61 | void ErrorNewDeleteTypeMismatch::Print() { |
62 | Decorator d; |
63 | Printf(format: "%s" , d.Error()); |
64 | Report(format: "ERROR: AddressSanitizer: %s on %p in thread %s:\n" , |
65 | scariness.GetDescription(), (void *)addr_description.addr, |
66 | AsanThreadIdAndName(tid).c_str()); |
67 | Printf(format: "%s object passed to delete has wrong type:\n" , d.Default()); |
68 | if (delete_size != 0) { |
69 | Printf( |
70 | format: " size of the allocated type: %zd bytes;\n" |
71 | " size of the deallocated type: %zd bytes.\n" , |
72 | addr_description.chunk_access.chunk_size, delete_size); |
73 | } |
74 | const uptr user_alignment = |
75 | addr_description.chunk_access.user_requested_alignment; |
76 | if (delete_alignment != user_alignment) { |
77 | char user_alignment_str[32]; |
78 | char delete_alignment_str[32]; |
79 | internal_snprintf(buffer: user_alignment_str, length: sizeof(user_alignment_str), |
80 | format: "%zd bytes" , user_alignment); |
81 | internal_snprintf(buffer: delete_alignment_str, length: sizeof(delete_alignment_str), |
82 | format: "%zd bytes" , delete_alignment); |
83 | static const char *kDefaultAlignment = "default-aligned" ; |
84 | Printf( |
85 | format: " alignment of the allocated type: %s;\n" |
86 | " alignment of the deallocated type: %s.\n" , |
87 | user_alignment > 0 ? user_alignment_str : kDefaultAlignment, |
88 | delete_alignment > 0 ? delete_alignment_str : kDefaultAlignment); |
89 | } |
90 | CHECK_GT(free_stack->size, 0); |
91 | scariness.Print(); |
92 | GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp); |
93 | stack.Print(); |
94 | addr_description.Print(); |
95 | ReportErrorSummary(error_type: scariness.GetDescription(), trace: &stack); |
96 | Report( |
97 | format: "HINT: if you don't care about these errors you may set " |
98 | "ASAN_OPTIONS=new_delete_type_mismatch=0\n" ); |
99 | } |
100 | |
101 | void ErrorFreeNotMalloced::Print() { |
102 | Decorator d; |
103 | Printf(format: "%s" , d.Error()); |
104 | Report( |
105 | format: "ERROR: AddressSanitizer: attempting free on address " |
106 | "which was not malloc()-ed: %p in thread %s\n" , |
107 | (void *)addr_description.Address(), AsanThreadIdAndName(tid).c_str()); |
108 | Printf(format: "%s" , d.Default()); |
109 | CHECK_GT(free_stack->size, 0); |
110 | scariness.Print(); |
111 | GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp); |
112 | stack.Print(); |
113 | addr_description.Print(); |
114 | ReportErrorSummary(error_type: scariness.GetDescription(), trace: &stack); |
115 | } |
116 | |
117 | void ErrorAllocTypeMismatch::Print() { |
118 | static const char *alloc_names[] = {"INVALID" , "malloc" , "operator new" , |
119 | "operator new []" }; |
120 | static const char *dealloc_names[] = {"INVALID" , "free" , "operator delete" , |
121 | "operator delete []" }; |
122 | CHECK_NE(alloc_type, dealloc_type); |
123 | Decorator d; |
124 | Printf(format: "%s" , d.Error()); |
125 | Report(format: "ERROR: AddressSanitizer: %s (%s vs %s) on %p\n" , |
126 | scariness.GetDescription(), alloc_names[alloc_type], |
127 | dealloc_names[dealloc_type], (void *)addr_description.Address()); |
128 | Printf(format: "%s" , d.Default()); |
129 | CHECK_GT(dealloc_stack->size, 0); |
130 | scariness.Print(); |
131 | GET_STACK_TRACE_FATAL(dealloc_stack->trace[0], dealloc_stack->top_frame_bp); |
132 | stack.Print(); |
133 | addr_description.Print(); |
134 | ReportErrorSummary(error_type: scariness.GetDescription(), trace: &stack); |
135 | Report( |
136 | format: "HINT: if you don't care about these errors you may set " |
137 | "ASAN_OPTIONS=alloc_dealloc_mismatch=0\n" ); |
138 | } |
139 | |
140 | void ErrorMallocUsableSizeNotOwned::Print() { |
141 | Decorator d; |
142 | Printf(format: "%s" , d.Error()); |
143 | Report( |
144 | format: "ERROR: AddressSanitizer: attempting to call malloc_usable_size() for " |
145 | "pointer which is not owned: %p\n" , |
146 | (void *)addr_description.Address()); |
147 | Printf(format: "%s" , d.Default()); |
148 | stack->Print(); |
149 | addr_description.Print(); |
150 | ReportErrorSummary(error_type: scariness.GetDescription(), trace: stack); |
151 | } |
152 | |
153 | void ErrorSanitizerGetAllocatedSizeNotOwned::Print() { |
154 | Decorator d; |
155 | Printf(format: "%s" , d.Error()); |
156 | Report( |
157 | format: "ERROR: AddressSanitizer: attempting to call " |
158 | "__sanitizer_get_allocated_size() for pointer which is not owned: %p\n" , |
159 | (void *)addr_description.Address()); |
160 | Printf(format: "%s" , d.Default()); |
161 | stack->Print(); |
162 | addr_description.Print(); |
163 | ReportErrorSummary(error_type: scariness.GetDescription(), trace: stack); |
164 | } |
165 | |
166 | void ErrorCallocOverflow::Print() { |
167 | Decorator d; |
168 | Printf(format: "%s" , d.Error()); |
169 | Report( |
170 | format: "ERROR: AddressSanitizer: calloc parameters overflow: count * size " |
171 | "(%zd * %zd) cannot be represented in type size_t (thread %s)\n" , |
172 | count, size, AsanThreadIdAndName(tid).c_str()); |
173 | Printf(format: "%s" , d.Default()); |
174 | stack->Print(); |
175 | PrintHintAllocatorCannotReturnNull(); |
176 | ReportErrorSummary(error_type: scariness.GetDescription(), trace: stack); |
177 | } |
178 | |
179 | void ErrorReallocArrayOverflow::Print() { |
180 | Decorator d; |
181 | Printf(format: "%s" , d.Error()); |
182 | Report( |
183 | format: "ERROR: AddressSanitizer: reallocarray parameters overflow: count * size " |
184 | "(%zd * %zd) cannot be represented in type size_t (thread %s)\n" , |
185 | count, size, AsanThreadIdAndName(tid).c_str()); |
186 | Printf(format: "%s" , d.Default()); |
187 | stack->Print(); |
188 | PrintHintAllocatorCannotReturnNull(); |
189 | ReportErrorSummary(error_type: scariness.GetDescription(), trace: stack); |
190 | } |
191 | |
192 | void ErrorPvallocOverflow::Print() { |
193 | Decorator d; |
194 | Printf(format: "%s" , d.Error()); |
195 | Report( |
196 | format: "ERROR: AddressSanitizer: pvalloc parameters overflow: size 0x%zx " |
197 | "rounded up to system page size 0x%zx cannot be represented in type " |
198 | "size_t (thread %s)\n" , |
199 | size, GetPageSizeCached(), AsanThreadIdAndName(tid).c_str()); |
200 | Printf(format: "%s" , d.Default()); |
201 | stack->Print(); |
202 | PrintHintAllocatorCannotReturnNull(); |
203 | ReportErrorSummary(error_type: scariness.GetDescription(), trace: stack); |
204 | } |
205 | |
206 | void ErrorInvalidAllocationAlignment::Print() { |
207 | Decorator d; |
208 | Printf(format: "%s" , d.Error()); |
209 | Report( |
210 | format: "ERROR: AddressSanitizer: invalid allocation alignment: %zd, " |
211 | "alignment must be a power of two (thread %s)\n" , |
212 | alignment, AsanThreadIdAndName(tid).c_str()); |
213 | Printf(format: "%s" , d.Default()); |
214 | stack->Print(); |
215 | PrintHintAllocatorCannotReturnNull(); |
216 | ReportErrorSummary(error_type: scariness.GetDescription(), trace: stack); |
217 | } |
218 | |
219 | void ErrorInvalidAlignedAllocAlignment::Print() { |
220 | Decorator d; |
221 | Printf(format: "%s" , d.Error()); |
222 | #if SANITIZER_POSIX |
223 | Report(format: "ERROR: AddressSanitizer: invalid alignment requested in " |
224 | "aligned_alloc: %zd, alignment must be a power of two and the " |
225 | "requested size 0x%zx must be a multiple of alignment " |
226 | "(thread %s)\n" , alignment, size, AsanThreadIdAndName(tid).c_str()); |
227 | #else |
228 | Report("ERROR: AddressSanitizer: invalid alignment requested in " |
229 | "aligned_alloc: %zd, the requested size 0x%zx must be a multiple of " |
230 | "alignment (thread %s)\n" , alignment, size, |
231 | AsanThreadIdAndName(tid).c_str()); |
232 | #endif |
233 | Printf(format: "%s" , d.Default()); |
234 | stack->Print(); |
235 | PrintHintAllocatorCannotReturnNull(); |
236 | ReportErrorSummary(error_type: scariness.GetDescription(), trace: stack); |
237 | } |
238 | |
239 | void ErrorInvalidPosixMemalignAlignment::Print() { |
240 | Decorator d; |
241 | Printf(format: "%s" , d.Error()); |
242 | Report( |
243 | format: "ERROR: AddressSanitizer: invalid alignment requested in posix_memalign: " |
244 | "%zd, alignment must be a power of two and a multiple of sizeof(void*) " |
245 | "== %zd (thread %s)\n" , |
246 | alignment, sizeof(void *), AsanThreadIdAndName(tid).c_str()); |
247 | Printf(format: "%s" , d.Default()); |
248 | stack->Print(); |
249 | PrintHintAllocatorCannotReturnNull(); |
250 | ReportErrorSummary(error_type: scariness.GetDescription(), trace: stack); |
251 | } |
252 | |
253 | void ErrorAllocationSizeTooBig::Print() { |
254 | Decorator d; |
255 | Printf(format: "%s" , d.Error()); |
256 | Report( |
257 | format: "ERROR: AddressSanitizer: requested allocation size 0x%zx (0x%zx after " |
258 | "adjustments for alignment, red zones etc.) exceeds maximum supported " |
259 | "size of 0x%zx (thread %s)\n" , |
260 | user_size, total_size, max_size, AsanThreadIdAndName(tid).c_str()); |
261 | Printf(format: "%s" , d.Default()); |
262 | stack->Print(); |
263 | PrintHintAllocatorCannotReturnNull(); |
264 | ReportErrorSummary(error_type: scariness.GetDescription(), trace: stack); |
265 | } |
266 | |
267 | void ErrorRssLimitExceeded::() { |
268 | Decorator d; |
269 | Printf(format: "%s" , d.Error()); |
270 | Report( |
271 | format: "ERROR: AddressSanitizer: specified RSS limit exceeded, currently set to " |
272 | "soft_rss_limit_mb=%zd\n" , common_flags()->soft_rss_limit_mb); |
273 | Printf(format: "%s" , d.Default()); |
274 | stack->Print(); |
275 | PrintHintAllocatorCannotReturnNull(); |
276 | ReportErrorSummary(error_type: scariness.GetDescription(), trace: stack); |
277 | } |
278 | |
279 | void ErrorOutOfMemory::Print() { |
280 | Decorator d; |
281 | Printf(format: "%s" , d.Error()); |
282 | ERROR_OOM("allocator is trying to allocate 0x%zx bytes\n" , requested_size); |
283 | Printf(format: "%s" , d.Default()); |
284 | stack->Print(); |
285 | PrintHintAllocatorCannotReturnNull(); |
286 | ReportErrorSummary(error_type: scariness.GetDescription(), trace: stack); |
287 | } |
288 | |
289 | void ErrorStringFunctionMemoryRangesOverlap::Print() { |
290 | Decorator d; |
291 | char bug_type[100]; |
292 | internal_snprintf(buffer: bug_type, length: sizeof(bug_type), format: "%s-param-overlap" , function); |
293 | Printf(format: "%s" , d.Error()); |
294 | Report( |
295 | format: "ERROR: AddressSanitizer: %s: memory ranges [%p,%p) and [%p, %p) " |
296 | "overlap\n" , |
297 | bug_type, (void *)addr1_description.Address(), |
298 | (void *)(addr1_description.Address() + length1), |
299 | (void *)addr2_description.Address(), |
300 | (void *)(addr2_description.Address() + length2)); |
301 | Printf(format: "%s" , d.Default()); |
302 | scariness.Print(); |
303 | stack->Print(); |
304 | addr1_description.Print(); |
305 | addr2_description.Print(); |
306 | ReportErrorSummary(error_type: bug_type, trace: stack); |
307 | } |
308 | |
309 | void ErrorStringFunctionSizeOverflow::Print() { |
310 | Decorator d; |
311 | Printf(format: "%s" , d.Error()); |
312 | Report(format: "ERROR: AddressSanitizer: %s: (size=%zd)\n" , |
313 | scariness.GetDescription(), size); |
314 | Printf(format: "%s" , d.Default()); |
315 | scariness.Print(); |
316 | stack->Print(); |
317 | addr_description.Print(); |
318 | ReportErrorSummary(error_type: scariness.GetDescription(), trace: stack); |
319 | } |
320 | |
321 | void ErrorBadParamsToAnnotateContiguousContainer::Print() { |
322 | Report( |
323 | format: "ERROR: AddressSanitizer: bad parameters to " |
324 | "__sanitizer_annotate_contiguous_container:\n" |
325 | " beg : %p\n" |
326 | " end : %p\n" |
327 | " old_mid : %p\n" |
328 | " new_mid : %p\n" , |
329 | (void *)beg, (void *)end, (void *)old_mid, (void *)new_mid); |
330 | uptr granularity = ASAN_SHADOW_GRANULARITY; |
331 | if (!IsAligned(a: beg, alignment: granularity)) |
332 | Report(format: "ERROR: beg is not aligned by %zu\n" , granularity); |
333 | stack->Print(); |
334 | ReportErrorSummary(error_type: scariness.GetDescription(), trace: stack); |
335 | } |
336 | |
337 | void ErrorBadParamsToAnnotateDoubleEndedContiguousContainer::Print() { |
338 | Report( |
339 | format: "ERROR: AddressSanitizer: bad parameters to " |
340 | "__sanitizer_annotate_double_ended_contiguous_container:\n" |
341 | " storage_beg : %p\n" |
342 | " storage_end : %p\n" |
343 | " old_container_beg : %p\n" |
344 | " old_container_end : %p\n" |
345 | " new_container_beg : %p\n" |
346 | " new_container_end : %p\n" , |
347 | (void *)storage_beg, (void *)storage_end, (void *)old_container_beg, |
348 | (void *)old_container_end, (void *)new_container_beg, |
349 | (void *)new_container_end); |
350 | uptr granularity = ASAN_SHADOW_GRANULARITY; |
351 | if (!IsAligned(a: storage_beg, alignment: granularity)) |
352 | Report(format: "ERROR: storage_beg is not aligned by %zu\n" , granularity); |
353 | stack->Print(); |
354 | ReportErrorSummary(error_type: scariness.GetDescription(), trace: stack); |
355 | } |
356 | |
357 | void ErrorODRViolation::Print() { |
358 | Decorator d; |
359 | Printf(format: "%s" , d.Error()); |
360 | Report(format: "ERROR: AddressSanitizer: %s (%p):\n" , scariness.GetDescription(), |
361 | (void *)global1.beg); |
362 | Printf(format: "%s" , d.Default()); |
363 | InternalScopedString g1_loc; |
364 | InternalScopedString g2_loc; |
365 | PrintGlobalLocation(str: &g1_loc, g: global1, /*print_module_name=*/true); |
366 | PrintGlobalLocation(str: &g2_loc, g: global2, /*print_module_name=*/true); |
367 | Printf(format: " [1] size=%zd '%s' %s\n" , global1.size, |
368 | MaybeDemangleGlobalName(name: global1.name), g1_loc.data()); |
369 | Printf(format: " [2] size=%zd '%s' %s\n" , global2.size, |
370 | MaybeDemangleGlobalName(name: global2.name), g2_loc.data()); |
371 | if (stack_id1 && stack_id2) { |
372 | Printf(format: "These globals were registered at these points:\n" ); |
373 | Printf(format: " [1]:\n" ); |
374 | StackDepotGet(id: stack_id1).Print(); |
375 | Printf(format: " [2]:\n" ); |
376 | StackDepotGet(id: stack_id2).Print(); |
377 | } |
378 | Report( |
379 | format: "HINT: if you don't care about these errors you may set " |
380 | "ASAN_OPTIONS=detect_odr_violation=0\n" ); |
381 | InternalScopedString error_msg; |
382 | error_msg.AppendF(format: "%s: global '%s' at %s" , scariness.GetDescription(), |
383 | MaybeDemangleGlobalName(name: global1.name), g1_loc.data()); |
384 | ReportErrorSummary(error_message: error_msg.data()); |
385 | } |
386 | |
387 | void ErrorInvalidPointerPair::Print() { |
388 | Decorator d; |
389 | Printf(format: "%s" , d.Error()); |
390 | Report(format: "ERROR: AddressSanitizer: %s: %p %p\n" , scariness.GetDescription(), |
391 | (void *)addr1_description.Address(), |
392 | (void *)addr2_description.Address()); |
393 | Printf(format: "%s" , d.Default()); |
394 | GET_STACK_TRACE_FATAL(pc, bp); |
395 | stack.Print(); |
396 | addr1_description.Print(); |
397 | addr2_description.Print(); |
398 | ReportErrorSummary(error_type: scariness.GetDescription(), trace: &stack); |
399 | } |
400 | |
401 | static bool AdjacentShadowValuesAreFullyPoisoned(u8 *s) { |
402 | return s[-1] > 127 && s[1] > 127; |
403 | } |
404 | |
405 | ErrorGeneric::ErrorGeneric(u32 tid, uptr pc_, uptr bp_, uptr sp_, uptr addr, |
406 | bool is_write_, uptr access_size_) |
407 | : ErrorBase(tid), |
408 | addr_description(addr, access_size_, /*shouldLockThreadRegistry=*/false), |
409 | pc(pc_), |
410 | bp(bp_), |
411 | sp(sp_), |
412 | access_size(access_size_), |
413 | is_write(is_write_), |
414 | shadow_val(0) { |
415 | scariness.Clear(); |
416 | if (access_size) { |
417 | if (access_size <= 9) { |
418 | char desr[] = "?-byte" ; |
419 | desr[0] = '0' + access_size; |
420 | scariness.Scare(add_to_score: access_size + access_size / 2, reason: desr); |
421 | } else if (access_size >= 10) { |
422 | scariness.Scare(add_to_score: 15, reason: "multi-byte" ); |
423 | } |
424 | is_write ? scariness.Scare(add_to_score: 20, reason: "write" ) : scariness.Scare(add_to_score: 1, reason: "read" ); |
425 | |
426 | // Determine the error type. |
427 | bug_descr = "unknown-crash" ; |
428 | if (AddrIsInMem(a: addr)) { |
429 | u8 *shadow_addr = (u8 *)MemToShadow(p: addr); |
430 | // If we are accessing 16 bytes, look at the second shadow byte. |
431 | if (*shadow_addr == 0 && access_size > ASAN_SHADOW_GRANULARITY) |
432 | shadow_addr++; |
433 | // If we are in the partial right redzone, look at the next shadow byte. |
434 | if (*shadow_addr > 0 && *shadow_addr < 128) shadow_addr++; |
435 | bool far_from_bounds = false; |
436 | shadow_val = *shadow_addr; |
437 | int bug_type_score = 0; |
438 | // For use-after-frees reads are almost as bad as writes. |
439 | int read_after_free_bonus = 0; |
440 | switch (shadow_val) { |
441 | case kAsanHeapLeftRedzoneMagic: |
442 | case kAsanArrayCookieMagic: |
443 | bug_descr = "heap-buffer-overflow" ; |
444 | bug_type_score = 10; |
445 | far_from_bounds = AdjacentShadowValuesAreFullyPoisoned(s: shadow_addr); |
446 | break; |
447 | case kAsanHeapFreeMagic: |
448 | bug_descr = "heap-use-after-free" ; |
449 | bug_type_score = 20; |
450 | if (!is_write) read_after_free_bonus = 18; |
451 | break; |
452 | case kAsanStackLeftRedzoneMagic: |
453 | bug_descr = "stack-buffer-underflow" ; |
454 | bug_type_score = 25; |
455 | far_from_bounds = AdjacentShadowValuesAreFullyPoisoned(s: shadow_addr); |
456 | break; |
457 | case kAsanInitializationOrderMagic: |
458 | bug_descr = "initialization-order-fiasco" ; |
459 | bug_type_score = 1; |
460 | break; |
461 | case kAsanStackMidRedzoneMagic: |
462 | case kAsanStackRightRedzoneMagic: |
463 | bug_descr = "stack-buffer-overflow" ; |
464 | bug_type_score = 25; |
465 | far_from_bounds = AdjacentShadowValuesAreFullyPoisoned(s: shadow_addr); |
466 | break; |
467 | case kAsanStackAfterReturnMagic: |
468 | bug_descr = "stack-use-after-return" ; |
469 | bug_type_score = 30; |
470 | if (!is_write) read_after_free_bonus = 18; |
471 | break; |
472 | case kAsanUserPoisonedMemoryMagic: |
473 | bug_descr = "use-after-poison" ; |
474 | bug_type_score = 20; |
475 | break; |
476 | case kAsanContiguousContainerOOBMagic: |
477 | bug_descr = "container-overflow" ; |
478 | bug_type_score = 10; |
479 | break; |
480 | case kAsanStackUseAfterScopeMagic: |
481 | bug_descr = "stack-use-after-scope" ; |
482 | bug_type_score = 10; |
483 | break; |
484 | case kAsanGlobalRedzoneMagic: |
485 | bug_descr = "global-buffer-overflow" ; |
486 | bug_type_score = 10; |
487 | far_from_bounds = AdjacentShadowValuesAreFullyPoisoned(s: shadow_addr); |
488 | break; |
489 | case kAsanIntraObjectRedzone: |
490 | bug_descr = "intra-object-overflow" ; |
491 | bug_type_score = 10; |
492 | break; |
493 | case kAsanAllocaLeftMagic: |
494 | case kAsanAllocaRightMagic: |
495 | bug_descr = "dynamic-stack-buffer-overflow" ; |
496 | bug_type_score = 25; |
497 | far_from_bounds = AdjacentShadowValuesAreFullyPoisoned(s: shadow_addr); |
498 | break; |
499 | } |
500 | scariness.Scare(add_to_score: bug_type_score + read_after_free_bonus, reason: bug_descr); |
501 | if (far_from_bounds) scariness.Scare(add_to_score: 10, reason: "far-from-bounds" ); |
502 | } |
503 | } |
504 | } |
505 | |
506 | static void PrintContainerOverflowHint() { |
507 | Printf(format: "HINT: if you don't care about these errors you may set " |
508 | "ASAN_OPTIONS=detect_container_overflow=0.\n" |
509 | "If you suspect a false positive see also: " |
510 | "https://github.com/google/sanitizers/wiki/" |
511 | "AddressSanitizerContainerOverflow.\n" ); |
512 | } |
513 | |
514 | static void PrintShadowByte(InternalScopedString *str, const char *before, |
515 | u8 byte, const char *after = "\n" ) { |
516 | PrintMemoryByte(str, before, byte, /*in_shadow*/true, after); |
517 | } |
518 | |
519 | static void PrintLegend(InternalScopedString *str) { |
520 | str->AppendF( |
521 | format: "Shadow byte legend (one shadow byte represents %d " |
522 | "application bytes):\n" , |
523 | (int)ASAN_SHADOW_GRANULARITY); |
524 | PrintShadowByte(str, before: " Addressable: " , byte: 0); |
525 | str->AppendF(format: " Partially addressable: " ); |
526 | for (u8 i = 1; i < ASAN_SHADOW_GRANULARITY; i++) |
527 | PrintShadowByte(str, before: "" , byte: i, after: " " ); |
528 | str->AppendF(format: "\n" ); |
529 | PrintShadowByte(str, before: " Heap left redzone: " , |
530 | byte: kAsanHeapLeftRedzoneMagic); |
531 | PrintShadowByte(str, before: " Freed heap region: " , byte: kAsanHeapFreeMagic); |
532 | PrintShadowByte(str, before: " Stack left redzone: " , |
533 | byte: kAsanStackLeftRedzoneMagic); |
534 | PrintShadowByte(str, before: " Stack mid redzone: " , |
535 | byte: kAsanStackMidRedzoneMagic); |
536 | PrintShadowByte(str, before: " Stack right redzone: " , |
537 | byte: kAsanStackRightRedzoneMagic); |
538 | PrintShadowByte(str, before: " Stack after return: " , |
539 | byte: kAsanStackAfterReturnMagic); |
540 | PrintShadowByte(str, before: " Stack use after scope: " , |
541 | byte: kAsanStackUseAfterScopeMagic); |
542 | PrintShadowByte(str, before: " Global redzone: " , byte: kAsanGlobalRedzoneMagic); |
543 | PrintShadowByte(str, before: " Global init order: " , |
544 | byte: kAsanInitializationOrderMagic); |
545 | PrintShadowByte(str, before: " Poisoned by user: " , |
546 | byte: kAsanUserPoisonedMemoryMagic); |
547 | PrintShadowByte(str, before: " Container overflow: " , |
548 | byte: kAsanContiguousContainerOOBMagic); |
549 | PrintShadowByte(str, before: " Array cookie: " , |
550 | byte: kAsanArrayCookieMagic); |
551 | PrintShadowByte(str, before: " Intra object redzone: " , |
552 | byte: kAsanIntraObjectRedzone); |
553 | PrintShadowByte(str, before: " ASan internal: " , byte: kAsanInternalHeapMagic); |
554 | PrintShadowByte(str, before: " Left alloca redzone: " , byte: kAsanAllocaLeftMagic); |
555 | PrintShadowByte(str, before: " Right alloca redzone: " , byte: kAsanAllocaRightMagic); |
556 | } |
557 | |
558 | static void PrintShadowBytes(InternalScopedString *str, const char *before, |
559 | u8 *bytes, u8 *guilty, uptr n) { |
560 | Decorator d; |
561 | if (before) |
562 | str->AppendF(format: "%s%p:" , before, |
563 | (void *)ShadowToMem(p: reinterpret_cast<uptr>(bytes))); |
564 | for (uptr i = 0; i < n; i++) { |
565 | u8 *p = bytes + i; |
566 | const char *before = |
567 | p == guilty ? "[" : (p - 1 == guilty && i != 0) ? "" : " " ; |
568 | const char *after = p == guilty ? "]" : "" ; |
569 | PrintShadowByte(str, before, byte: *p, after); |
570 | } |
571 | str->AppendF(format: "\n" ); |
572 | } |
573 | |
574 | static void PrintShadowMemoryForAddress(uptr addr) { |
575 | if (!AddrIsInMem(a: addr)) return; |
576 | uptr shadow_addr = MemToShadow(p: addr); |
577 | const uptr n_bytes_per_row = 16; |
578 | uptr aligned_shadow = shadow_addr & ~(n_bytes_per_row - 1); |
579 | InternalScopedString str; |
580 | str.AppendF(format: "Shadow bytes around the buggy address:\n" ); |
581 | for (int i = -5; i <= 5; i++) { |
582 | uptr row_shadow_addr = aligned_shadow + i * n_bytes_per_row; |
583 | // Skip rows that would be outside the shadow range. This can happen when |
584 | // the user address is near the bottom, top, or shadow gap of the address |
585 | // space. |
586 | if (!AddrIsInShadow(a: row_shadow_addr)) continue; |
587 | const char *prefix = (i == 0) ? "=>" : " " ; |
588 | PrintShadowBytes(str: &str, before: prefix, bytes: (u8 *)row_shadow_addr, guilty: (u8 *)shadow_addr, |
589 | n: n_bytes_per_row); |
590 | } |
591 | if (flags()->print_legend) PrintLegend(str: &str); |
592 | Printf(format: "%s" , str.data()); |
593 | } |
594 | |
595 | void ErrorGeneric::Print() { |
596 | Decorator d; |
597 | Printf(format: "%s" , d.Error()); |
598 | uptr addr = addr_description.Address(); |
599 | Report(format: "ERROR: AddressSanitizer: %s on address %p at pc %p bp %p sp %p\n" , |
600 | bug_descr, (void *)addr, (void *)pc, (void *)bp, (void *)sp); |
601 | Printf(format: "%s" , d.Default()); |
602 | |
603 | Printf(format: "%s%s of size %zu at %p thread %s%s\n" , d.Access(), |
604 | access_size ? (is_write ? "WRITE" : "READ" ) : "ACCESS" , access_size, |
605 | (void *)addr, AsanThreadIdAndName(tid).c_str(), d.Default()); |
606 | |
607 | scariness.Print(); |
608 | GET_STACK_TRACE_FATAL(pc, bp); |
609 | stack.Print(); |
610 | |
611 | // Pass bug_descr because we have a special case for |
612 | // initialization-order-fiasco |
613 | addr_description.Print(bug_descr); |
614 | if (shadow_val == kAsanContiguousContainerOOBMagic) |
615 | PrintContainerOverflowHint(); |
616 | ReportErrorSummary(error_type: bug_descr, trace: &stack); |
617 | PrintShadowMemoryForAddress(addr); |
618 | } |
619 | |
620 | } // namespace __asan |
621 | |