1 | //===-- asan_errors.h -------------------------------------------*- 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-private header for error structures. |
12 | //===----------------------------------------------------------------------===// |
13 | #ifndef ASAN_ERRORS_H |
14 | #define ASAN_ERRORS_H |
15 | |
16 | #include "asan_descriptions.h" |
17 | #include "asan_scariness_score.h" |
18 | #include "sanitizer_common/sanitizer_common.h" |
19 | |
20 | namespace __asan { |
21 | |
22 | // (*) VS2013 does not implement unrestricted unions, so we need a trivial |
23 | // default constructor explicitly defined for each particular error. |
24 | |
25 | // None of the error classes own the stack traces mentioned in them. |
26 | |
27 | struct ErrorBase { |
28 | ScarinessScoreBase scariness; |
29 | u32 tid; |
30 | |
31 | ErrorBase() = default; // (*) |
32 | explicit ErrorBase(u32 tid_) : tid(tid_) {} |
33 | ErrorBase(u32 tid_, int initial_score, const char *reason) : tid(tid_) { |
34 | scariness.Clear(); |
35 | scariness.Scare(add_to_score: initial_score, reason); |
36 | } |
37 | }; |
38 | |
39 | struct ErrorDeadlySignal : ErrorBase { |
40 | SignalContext signal; |
41 | |
42 | ErrorDeadlySignal() = default; // (*) |
43 | ErrorDeadlySignal(u32 tid, const SignalContext &sig) |
44 | : ErrorBase(tid), |
45 | signal(sig) { |
46 | scariness.Clear(); |
47 | if (signal.IsStackOverflow()) { |
48 | scariness.Scare(add_to_score: 10, reason: "stack-overflow" ); |
49 | } else if (!signal.is_memory_access) { |
50 | scariness.Scare(add_to_score: 10, reason: "signal" ); |
51 | } else if (signal.is_true_faulting_addr && |
52 | signal.addr < GetPageSizeCached()) { |
53 | scariness.Scare(add_to_score: 10, reason: "null-deref" ); |
54 | } else if (signal.addr == signal.pc) { |
55 | scariness.Scare(add_to_score: 60, reason: "wild-jump" ); |
56 | } else if (signal.write_flag == SignalContext::Write) { |
57 | scariness.Scare(add_to_score: 30, reason: "wild-addr-write" ); |
58 | } else if (signal.write_flag == SignalContext::Read) { |
59 | scariness.Scare(add_to_score: 20, reason: "wild-addr-read" ); |
60 | } else { |
61 | scariness.Scare(add_to_score: 25, reason: "wild-addr" ); |
62 | } |
63 | } |
64 | void Print(); |
65 | }; |
66 | |
67 | struct ErrorDoubleFree : ErrorBase { |
68 | const BufferedStackTrace *second_free_stack; |
69 | HeapAddressDescription addr_description; |
70 | |
71 | ErrorDoubleFree() = default; // (*) |
72 | ErrorDoubleFree(u32 tid, BufferedStackTrace *stack, uptr addr) |
73 | : ErrorBase(tid, 42, "double-free" ), |
74 | second_free_stack(stack) { |
75 | CHECK_GT(second_free_stack->size, 0); |
76 | GetHeapAddressInformation(addr, access_size: 1, descr: &addr_description); |
77 | } |
78 | void Print(); |
79 | }; |
80 | |
81 | struct ErrorNewDeleteTypeMismatch : ErrorBase { |
82 | const BufferedStackTrace *free_stack; |
83 | HeapAddressDescription addr_description; |
84 | uptr delete_size; |
85 | uptr delete_alignment; |
86 | |
87 | ErrorNewDeleteTypeMismatch() = default; // (*) |
88 | ErrorNewDeleteTypeMismatch(u32 tid, BufferedStackTrace *stack, uptr addr, |
89 | uptr delete_size_, uptr delete_alignment_) |
90 | : ErrorBase(tid, 10, "new-delete-type-mismatch" ), |
91 | free_stack(stack), |
92 | delete_size(delete_size_), |
93 | delete_alignment(delete_alignment_) { |
94 | GetHeapAddressInformation(addr, access_size: 1, descr: &addr_description); |
95 | } |
96 | void Print(); |
97 | }; |
98 | |
99 | struct ErrorFreeNotMalloced : ErrorBase { |
100 | const BufferedStackTrace *free_stack; |
101 | AddressDescription addr_description; |
102 | |
103 | ErrorFreeNotMalloced() = default; // (*) |
104 | ErrorFreeNotMalloced(u32 tid, BufferedStackTrace *stack, uptr addr) |
105 | : ErrorBase(tid, 40, "bad-free" ), |
106 | free_stack(stack), |
107 | addr_description(addr, /*shouldLockThreadRegistry=*/false) {} |
108 | void Print(); |
109 | }; |
110 | |
111 | struct ErrorAllocTypeMismatch : ErrorBase { |
112 | const BufferedStackTrace *dealloc_stack; |
113 | AllocType alloc_type, dealloc_type; |
114 | AddressDescription addr_description; |
115 | |
116 | ErrorAllocTypeMismatch() = default; // (*) |
117 | ErrorAllocTypeMismatch(u32 tid, BufferedStackTrace *stack, uptr addr, |
118 | AllocType alloc_type_, AllocType dealloc_type_) |
119 | : ErrorBase(tid, 10, "alloc-dealloc-mismatch" ), |
120 | dealloc_stack(stack), |
121 | alloc_type(alloc_type_), |
122 | dealloc_type(dealloc_type_), |
123 | addr_description(addr, 1, false) {} |
124 | void Print(); |
125 | }; |
126 | |
127 | struct ErrorMallocUsableSizeNotOwned : ErrorBase { |
128 | const BufferedStackTrace *stack; |
129 | AddressDescription addr_description; |
130 | |
131 | ErrorMallocUsableSizeNotOwned() = default; // (*) |
132 | ErrorMallocUsableSizeNotOwned(u32 tid, BufferedStackTrace *stack_, uptr addr) |
133 | : ErrorBase(tid, 10, "bad-malloc_usable_size" ), |
134 | stack(stack_), |
135 | addr_description(addr, /*shouldLockThreadRegistry=*/false) {} |
136 | void Print(); |
137 | }; |
138 | |
139 | struct ErrorSanitizerGetAllocatedSizeNotOwned : ErrorBase { |
140 | const BufferedStackTrace *stack; |
141 | AddressDescription addr_description; |
142 | |
143 | ErrorSanitizerGetAllocatedSizeNotOwned() = default; // (*) |
144 | ErrorSanitizerGetAllocatedSizeNotOwned(u32 tid, BufferedStackTrace *stack_, |
145 | uptr addr) |
146 | : ErrorBase(tid, 10, "bad-__sanitizer_get_allocated_size" ), |
147 | stack(stack_), |
148 | addr_description(addr, /*shouldLockThreadRegistry=*/false) {} |
149 | void Print(); |
150 | }; |
151 | |
152 | struct ErrorCallocOverflow : ErrorBase { |
153 | const BufferedStackTrace *stack; |
154 | uptr count; |
155 | uptr size; |
156 | |
157 | ErrorCallocOverflow() = default; // (*) |
158 | ErrorCallocOverflow(u32 tid, BufferedStackTrace *stack_, uptr count_, |
159 | uptr size_) |
160 | : ErrorBase(tid, 10, "calloc-overflow" ), |
161 | stack(stack_), |
162 | count(count_), |
163 | size(size_) {} |
164 | void Print(); |
165 | }; |
166 | |
167 | struct ErrorReallocArrayOverflow : ErrorBase { |
168 | const BufferedStackTrace *stack; |
169 | uptr count; |
170 | uptr size; |
171 | |
172 | ErrorReallocArrayOverflow() = default; // (*) |
173 | ErrorReallocArrayOverflow(u32 tid, BufferedStackTrace *stack_, uptr count_, |
174 | uptr size_) |
175 | : ErrorBase(tid, 10, "reallocarray-overflow" ), |
176 | stack(stack_), |
177 | count(count_), |
178 | size(size_) {} |
179 | void Print(); |
180 | }; |
181 | |
182 | struct ErrorPvallocOverflow : ErrorBase { |
183 | const BufferedStackTrace *stack; |
184 | uptr size; |
185 | |
186 | ErrorPvallocOverflow() = default; // (*) |
187 | ErrorPvallocOverflow(u32 tid, BufferedStackTrace *stack_, uptr size_) |
188 | : ErrorBase(tid, 10, "pvalloc-overflow" ), |
189 | stack(stack_), |
190 | size(size_) {} |
191 | void Print(); |
192 | }; |
193 | |
194 | struct ErrorInvalidAllocationAlignment : ErrorBase { |
195 | const BufferedStackTrace *stack; |
196 | uptr alignment; |
197 | |
198 | ErrorInvalidAllocationAlignment() = default; // (*) |
199 | ErrorInvalidAllocationAlignment(u32 tid, BufferedStackTrace *stack_, |
200 | uptr alignment_) |
201 | : ErrorBase(tid, 10, "invalid-allocation-alignment" ), |
202 | stack(stack_), |
203 | alignment(alignment_) {} |
204 | void Print(); |
205 | }; |
206 | |
207 | struct ErrorInvalidAlignedAllocAlignment : ErrorBase { |
208 | const BufferedStackTrace *stack; |
209 | uptr size; |
210 | uptr alignment; |
211 | |
212 | ErrorInvalidAlignedAllocAlignment() = default; // (*) |
213 | ErrorInvalidAlignedAllocAlignment(u32 tid, BufferedStackTrace *stack_, |
214 | uptr size_, uptr alignment_) |
215 | : ErrorBase(tid, 10, "invalid-aligned-alloc-alignment" ), |
216 | stack(stack_), |
217 | size(size_), |
218 | alignment(alignment_) {} |
219 | void Print(); |
220 | }; |
221 | |
222 | struct ErrorInvalidPosixMemalignAlignment : ErrorBase { |
223 | const BufferedStackTrace *stack; |
224 | uptr alignment; |
225 | |
226 | ErrorInvalidPosixMemalignAlignment() = default; // (*) |
227 | ErrorInvalidPosixMemalignAlignment(u32 tid, BufferedStackTrace *stack_, |
228 | uptr alignment_) |
229 | : ErrorBase(tid, 10, "invalid-posix-memalign-alignment" ), |
230 | stack(stack_), |
231 | alignment(alignment_) {} |
232 | void Print(); |
233 | }; |
234 | |
235 | struct ErrorAllocationSizeTooBig : ErrorBase { |
236 | const BufferedStackTrace *stack; |
237 | uptr user_size; |
238 | uptr total_size; |
239 | uptr max_size; |
240 | |
241 | ErrorAllocationSizeTooBig() = default; // (*) |
242 | ErrorAllocationSizeTooBig(u32 tid, BufferedStackTrace *stack_, |
243 | uptr user_size_, uptr total_size_, uptr max_size_) |
244 | : ErrorBase(tid, 10, "allocation-size-too-big" ), |
245 | stack(stack_), |
246 | user_size(user_size_), |
247 | total_size(total_size_), |
248 | max_size(max_size_) {} |
249 | void Print(); |
250 | }; |
251 | |
252 | struct : ErrorBase { |
253 | const BufferedStackTrace *; |
254 | |
255 | () = default; // (*) |
256 | (u32 tid, BufferedStackTrace *stack_) |
257 | : ErrorBase(tid, 10, "rss-limit-exceeded" ), |
258 | stack(stack_) {} |
259 | void (); |
260 | }; |
261 | |
262 | struct ErrorOutOfMemory : ErrorBase { |
263 | const BufferedStackTrace *stack; |
264 | uptr requested_size; |
265 | |
266 | ErrorOutOfMemory() = default; // (*) |
267 | ErrorOutOfMemory(u32 tid, BufferedStackTrace *stack_, uptr requested_size_) |
268 | : ErrorBase(tid, 10, "out-of-memory" ), |
269 | stack(stack_), |
270 | requested_size(requested_size_) {} |
271 | void Print(); |
272 | }; |
273 | |
274 | struct ErrorStringFunctionMemoryRangesOverlap : ErrorBase { |
275 | const BufferedStackTrace *stack; |
276 | uptr length1, length2; |
277 | AddressDescription addr1_description; |
278 | AddressDescription addr2_description; |
279 | const char *function; |
280 | |
281 | ErrorStringFunctionMemoryRangesOverlap() = default; // (*) |
282 | ErrorStringFunctionMemoryRangesOverlap(u32 tid, BufferedStackTrace *stack_, |
283 | uptr addr1, uptr length1_, uptr addr2, |
284 | uptr length2_, const char *function_) |
285 | : ErrorBase(tid), |
286 | stack(stack_), |
287 | length1(length1_), |
288 | length2(length2_), |
289 | addr1_description(addr1, length1, /*shouldLockThreadRegistry=*/false), |
290 | addr2_description(addr2, length2, /*shouldLockThreadRegistry=*/false), |
291 | function(function_) { |
292 | char bug_type[100]; |
293 | internal_snprintf(buffer: bug_type, length: sizeof(bug_type), format: "%s-param-overlap" , function); |
294 | scariness.Clear(); |
295 | scariness.Scare(add_to_score: 10, reason: bug_type); |
296 | } |
297 | void Print(); |
298 | }; |
299 | |
300 | struct ErrorStringFunctionSizeOverflow : ErrorBase { |
301 | const BufferedStackTrace *stack; |
302 | AddressDescription addr_description; |
303 | uptr size; |
304 | |
305 | ErrorStringFunctionSizeOverflow() = default; // (*) |
306 | ErrorStringFunctionSizeOverflow(u32 tid, BufferedStackTrace *stack_, |
307 | uptr addr, uptr size_) |
308 | : ErrorBase(tid, 10, "negative-size-param" ), |
309 | stack(stack_), |
310 | addr_description(addr, /*shouldLockThreadRegistry=*/false), |
311 | size(size_) {} |
312 | void Print(); |
313 | }; |
314 | |
315 | struct ErrorBadParamsToAnnotateContiguousContainer : ErrorBase { |
316 | const BufferedStackTrace *stack; |
317 | uptr beg, end, old_mid, new_mid; |
318 | |
319 | ErrorBadParamsToAnnotateContiguousContainer() = default; // (*) |
320 | // PS4: Do we want an AddressDescription for beg? |
321 | ErrorBadParamsToAnnotateContiguousContainer(u32 tid, |
322 | BufferedStackTrace *stack_, |
323 | uptr beg_, uptr end_, |
324 | uptr old_mid_, uptr new_mid_) |
325 | : ErrorBase(tid, 10, "bad-__sanitizer_annotate_contiguous_container" ), |
326 | stack(stack_), |
327 | beg(beg_), |
328 | end(end_), |
329 | old_mid(old_mid_), |
330 | new_mid(new_mid_) {} |
331 | void Print(); |
332 | }; |
333 | |
334 | struct ErrorBadParamsToAnnotateDoubleEndedContiguousContainer : ErrorBase { |
335 | const BufferedStackTrace *stack; |
336 | uptr storage_beg, storage_end, old_container_beg, old_container_end, |
337 | new_container_beg, new_container_end; |
338 | |
339 | ErrorBadParamsToAnnotateDoubleEndedContiguousContainer() = default; // (*) |
340 | ErrorBadParamsToAnnotateDoubleEndedContiguousContainer( |
341 | u32 tid, BufferedStackTrace *stack_, uptr storage_beg_, uptr storage_end_, |
342 | uptr old_container_beg_, uptr old_container_end_, uptr new_container_beg_, |
343 | uptr new_container_end_) |
344 | : ErrorBase(tid, 10, |
345 | "bad-__sanitizer_annotate_double_ended_contiguous_container" ), |
346 | stack(stack_), |
347 | storage_beg(storage_beg_), |
348 | storage_end(storage_end_), |
349 | old_container_beg(old_container_beg_), |
350 | old_container_end(old_container_end_), |
351 | new_container_beg(new_container_beg_), |
352 | new_container_end(new_container_end_) {} |
353 | void Print(); |
354 | }; |
355 | |
356 | struct ErrorODRViolation : ErrorBase { |
357 | __asan_global global1, global2; |
358 | u32 stack_id1, stack_id2; |
359 | |
360 | ErrorODRViolation() = default; // (*) |
361 | ErrorODRViolation(u32 tid, const __asan_global *g1, u32 stack_id1_, |
362 | const __asan_global *g2, u32 stack_id2_) |
363 | : ErrorBase(tid, 10, "odr-violation" ), |
364 | global1(*g1), |
365 | global2(*g2), |
366 | stack_id1(stack_id1_), |
367 | stack_id2(stack_id2_) {} |
368 | void Print(); |
369 | }; |
370 | |
371 | struct ErrorInvalidPointerPair : ErrorBase { |
372 | uptr pc, bp, sp; |
373 | AddressDescription addr1_description; |
374 | AddressDescription addr2_description; |
375 | |
376 | ErrorInvalidPointerPair() = default; // (*) |
377 | ErrorInvalidPointerPair(u32 tid, uptr pc_, uptr bp_, uptr sp_, uptr p1, |
378 | uptr p2) |
379 | : ErrorBase(tid, 10, "invalid-pointer-pair" ), |
380 | pc(pc_), |
381 | bp(bp_), |
382 | sp(sp_), |
383 | addr1_description(p1, 1, /*shouldLockThreadRegistry=*/false), |
384 | addr2_description(p2, 1, /*shouldLockThreadRegistry=*/false) {} |
385 | void Print(); |
386 | }; |
387 | |
388 | struct ErrorGeneric : ErrorBase { |
389 | AddressDescription addr_description; |
390 | uptr pc, bp, sp; |
391 | uptr access_size; |
392 | const char *bug_descr; |
393 | bool is_write; |
394 | u8 shadow_val; |
395 | |
396 | ErrorGeneric() = default; // (*) |
397 | ErrorGeneric(u32 tid, uptr pc_, uptr bp_, uptr sp_, uptr addr, bool is_write_, |
398 | uptr access_size_); |
399 | void Print(); |
400 | }; |
401 | |
402 | // clang-format off |
403 | #define ASAN_FOR_EACH_ERROR_KIND(macro) \ |
404 | macro(DeadlySignal) \ |
405 | macro(DoubleFree) \ |
406 | macro(NewDeleteTypeMismatch) \ |
407 | macro(FreeNotMalloced) \ |
408 | macro(AllocTypeMismatch) \ |
409 | macro(MallocUsableSizeNotOwned) \ |
410 | macro(SanitizerGetAllocatedSizeNotOwned) \ |
411 | macro(CallocOverflow) \ |
412 | macro(ReallocArrayOverflow) \ |
413 | macro(PvallocOverflow) \ |
414 | macro(InvalidAllocationAlignment) \ |
415 | macro(InvalidAlignedAllocAlignment) \ |
416 | macro(InvalidPosixMemalignAlignment) \ |
417 | macro(AllocationSizeTooBig) \ |
418 | macro() \ |
419 | macro(OutOfMemory) \ |
420 | macro(StringFunctionMemoryRangesOverlap) \ |
421 | macro(StringFunctionSizeOverflow) \ |
422 | macro(BadParamsToAnnotateContiguousContainer) \ |
423 | macro(BadParamsToAnnotateDoubleEndedContiguousContainer) \ |
424 | macro(ODRViolation) \ |
425 | macro(InvalidPointerPair) \ |
426 | macro(Generic) |
427 | // clang-format on |
428 | |
429 | #define ASAN_DEFINE_ERROR_KIND(name) kErrorKind##name, |
430 | #define ASAN_ERROR_DESCRIPTION_MEMBER(name) Error##name name; |
431 | #define ASAN_ERROR_DESCRIPTION_CONSTRUCTOR(name) \ |
432 | ErrorDescription(Error##name const &e) : kind(kErrorKind##name) { \ |
433 | internal_memcpy(&name, &e, sizeof(name)); \ |
434 | } |
435 | #define ASAN_ERROR_DESCRIPTION_PRINT(name) \ |
436 | case kErrorKind##name: \ |
437 | return name.Print(); |
438 | |
439 | enum ErrorKind { |
440 | kErrorKindInvalid = 0, |
441 | ASAN_FOR_EACH_ERROR_KIND(ASAN_DEFINE_ERROR_KIND) |
442 | }; |
443 | |
444 | struct ErrorDescription { |
445 | ErrorKind kind; |
446 | // We're using a tagged union because it allows us to have a trivially |
447 | // copiable type and use the same structures as the public interface. |
448 | // |
449 | // We can add a wrapper around it to make it "more c++-like", but that would |
450 | // add a lot of code and the benefit wouldn't be that big. |
451 | union { |
452 | ErrorBase Base; |
453 | ASAN_FOR_EACH_ERROR_KIND(ASAN_ERROR_DESCRIPTION_MEMBER) |
454 | }; |
455 | |
456 | ErrorDescription() { internal_memset(s: this, c: 0, n: sizeof(*this)); } |
457 | explicit ErrorDescription(LinkerInitialized) {} |
458 | ASAN_FOR_EACH_ERROR_KIND(ASAN_ERROR_DESCRIPTION_CONSTRUCTOR) |
459 | |
460 | bool IsValid() { return kind != kErrorKindInvalid; } |
461 | void Print() { |
462 | switch (kind) { |
463 | ASAN_FOR_EACH_ERROR_KIND(ASAN_ERROR_DESCRIPTION_PRINT) |
464 | case kErrorKindInvalid: |
465 | CHECK(0); |
466 | } |
467 | CHECK(0); |
468 | } |
469 | }; |
470 | |
471 | #undef ASAN_FOR_EACH_ERROR_KIND |
472 | #undef ASAN_DEFINE_ERROR_KIND |
473 | #undef ASAN_ERROR_DESCRIPTION_MEMBER |
474 | #undef ASAN_ERROR_DESCRIPTION_CONSTRUCTOR |
475 | #undef ASAN_ERROR_DESCRIPTION_PRINT |
476 | |
477 | } // namespace __asan |
478 | |
479 | #endif // ASAN_ERRORS_H |
480 | |