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
20namespace __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
27struct 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
39struct 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
67struct 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
81struct 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
99struct ErrorFreeSizeMismatch : ErrorBase {
100 const BufferedStackTrace* free_stack;
101 HeapAddressDescription addr_description;
102 uptr delete_size;
103 uptr delete_alignment;
104
105 ErrorFreeSizeMismatch() = default; // (*)
106 ErrorFreeSizeMismatch(u32 tid, BufferedStackTrace* stack, uptr addr,
107 uptr delete_size, uptr delete_alignment)
108 : ErrorBase(tid, 10, "free-size-mismatch"),
109 free_stack(stack),
110 delete_size(delete_size),
111 delete_alignment(delete_alignment) {
112 GetHeapAddressInformation(addr, access_size: 1, descr: &addr_description);
113 }
114 void Print();
115 bool isFreeAlignedSized() const { return delete_alignment != 0; }
116};
117
118struct ErrorFreeNotMalloced : ErrorBase {
119 const BufferedStackTrace *free_stack;
120 AddressDescription addr_description;
121
122 ErrorFreeNotMalloced() = default; // (*)
123 ErrorFreeNotMalloced(u32 tid, BufferedStackTrace *stack, uptr addr)
124 : ErrorBase(tid, 40, "bad-free"),
125 free_stack(stack),
126 addr_description(addr, /*shouldLockThreadRegistry=*/false) {}
127 void Print();
128};
129
130struct ErrorAllocTypeMismatch : ErrorBase {
131 const BufferedStackTrace *dealloc_stack;
132 AllocType alloc_type, dealloc_type;
133 AddressDescription addr_description;
134
135 ErrorAllocTypeMismatch() = default; // (*)
136 ErrorAllocTypeMismatch(u32 tid, BufferedStackTrace *stack, uptr addr,
137 AllocType alloc_type_, AllocType dealloc_type_)
138 : ErrorBase(tid, 10, "alloc-dealloc-mismatch"),
139 dealloc_stack(stack),
140 alloc_type(alloc_type_),
141 dealloc_type(dealloc_type_),
142 addr_description(addr, 1, false) {}
143 void Print();
144};
145
146struct ErrorMallocUsableSizeNotOwned : ErrorBase {
147 const BufferedStackTrace *stack;
148 AddressDescription addr_description;
149
150 ErrorMallocUsableSizeNotOwned() = default; // (*)
151 ErrorMallocUsableSizeNotOwned(u32 tid, BufferedStackTrace *stack_, uptr addr)
152 : ErrorBase(tid, 10, "bad-malloc_usable_size"),
153 stack(stack_),
154 addr_description(addr, /*shouldLockThreadRegistry=*/false) {}
155 void Print();
156};
157
158struct ErrorSanitizerGetAllocatedSizeNotOwned : ErrorBase {
159 const BufferedStackTrace *stack;
160 AddressDescription addr_description;
161
162 ErrorSanitizerGetAllocatedSizeNotOwned() = default; // (*)
163 ErrorSanitizerGetAllocatedSizeNotOwned(u32 tid, BufferedStackTrace *stack_,
164 uptr addr)
165 : ErrorBase(tid, 10, "bad-__sanitizer_get_allocated_size"),
166 stack(stack_),
167 addr_description(addr, /*shouldLockThreadRegistry=*/false) {}
168 void Print();
169};
170
171struct ErrorCallocOverflow : ErrorBase {
172 const BufferedStackTrace *stack;
173 uptr count;
174 uptr size;
175
176 ErrorCallocOverflow() = default; // (*)
177 ErrorCallocOverflow(u32 tid, BufferedStackTrace *stack_, uptr count_,
178 uptr size_)
179 : ErrorBase(tid, 10, "calloc-overflow"),
180 stack(stack_),
181 count(count_),
182 size(size_) {}
183 void Print();
184};
185
186struct ErrorReallocArrayOverflow : ErrorBase {
187 const BufferedStackTrace *stack;
188 uptr count;
189 uptr size;
190
191 ErrorReallocArrayOverflow() = default; // (*)
192 ErrorReallocArrayOverflow(u32 tid, BufferedStackTrace *stack_, uptr count_,
193 uptr size_)
194 : ErrorBase(tid, 10, "reallocarray-overflow"),
195 stack(stack_),
196 count(count_),
197 size(size_) {}
198 void Print();
199};
200
201struct ErrorPvallocOverflow : ErrorBase {
202 const BufferedStackTrace *stack;
203 uptr size;
204
205 ErrorPvallocOverflow() = default; // (*)
206 ErrorPvallocOverflow(u32 tid, BufferedStackTrace *stack_, uptr size_)
207 : ErrorBase(tid, 10, "pvalloc-overflow"),
208 stack(stack_),
209 size(size_) {}
210 void Print();
211};
212
213struct ErrorInvalidAllocationAlignment : ErrorBase {
214 const BufferedStackTrace *stack;
215 uptr alignment;
216
217 ErrorInvalidAllocationAlignment() = default; // (*)
218 ErrorInvalidAllocationAlignment(u32 tid, BufferedStackTrace *stack_,
219 uptr alignment_)
220 : ErrorBase(tid, 10, "invalid-allocation-alignment"),
221 stack(stack_),
222 alignment(alignment_) {}
223 void Print();
224};
225
226struct ErrorInvalidAlignedAllocAlignment : ErrorBase {
227 const BufferedStackTrace *stack;
228 uptr size;
229 uptr alignment;
230
231 ErrorInvalidAlignedAllocAlignment() = default; // (*)
232 ErrorInvalidAlignedAllocAlignment(u32 tid, BufferedStackTrace *stack_,
233 uptr size_, uptr alignment_)
234 : ErrorBase(tid, 10, "invalid-aligned-alloc-alignment"),
235 stack(stack_),
236 size(size_),
237 alignment(alignment_) {}
238 void Print();
239};
240
241struct ErrorInvalidPosixMemalignAlignment : ErrorBase {
242 const BufferedStackTrace *stack;
243 uptr alignment;
244
245 ErrorInvalidPosixMemalignAlignment() = default; // (*)
246 ErrorInvalidPosixMemalignAlignment(u32 tid, BufferedStackTrace *stack_,
247 uptr alignment_)
248 : ErrorBase(tid, 10, "invalid-posix-memalign-alignment"),
249 stack(stack_),
250 alignment(alignment_) {}
251 void Print();
252};
253
254struct ErrorAllocationSizeTooBig : ErrorBase {
255 const BufferedStackTrace *stack;
256 uptr user_size;
257 uptr total_size;
258 uptr max_size;
259
260 ErrorAllocationSizeTooBig() = default; // (*)
261 ErrorAllocationSizeTooBig(u32 tid, BufferedStackTrace *stack_,
262 uptr user_size_, uptr total_size_, uptr max_size_)
263 : ErrorBase(tid, 10, "allocation-size-too-big"),
264 stack(stack_),
265 user_size(user_size_),
266 total_size(total_size_),
267 max_size(max_size_) {}
268 void Print();
269};
270
271struct ErrorRssLimitExceeded : ErrorBase {
272 const BufferedStackTrace *stack;
273
274 ErrorRssLimitExceeded() = default; // (*)
275 ErrorRssLimitExceeded(u32 tid, BufferedStackTrace *stack_)
276 : ErrorBase(tid, 10, "rss-limit-exceeded"),
277 stack(stack_) {}
278 void Print();
279};
280
281struct ErrorOutOfMemory : ErrorBase {
282 const BufferedStackTrace *stack;
283 uptr requested_size;
284
285 ErrorOutOfMemory() = default; // (*)
286 ErrorOutOfMemory(u32 tid, BufferedStackTrace *stack_, uptr requested_size_)
287 : ErrorBase(tid, 10, "out-of-memory"),
288 stack(stack_),
289 requested_size(requested_size_) {}
290 void Print();
291};
292
293struct ErrorStringFunctionMemoryRangesOverlap : ErrorBase {
294 const BufferedStackTrace *stack;
295 uptr length1, length2;
296 AddressDescription addr1_description;
297 AddressDescription addr2_description;
298 const char *function;
299
300 ErrorStringFunctionMemoryRangesOverlap() = default; // (*)
301 ErrorStringFunctionMemoryRangesOverlap(u32 tid, BufferedStackTrace *stack_,
302 uptr addr1, uptr length1_, uptr addr2,
303 uptr length2_, const char *function_)
304 : ErrorBase(tid),
305 stack(stack_),
306 length1(length1_),
307 length2(length2_),
308 addr1_description(addr1, length1, /*shouldLockThreadRegistry=*/false),
309 addr2_description(addr2, length2, /*shouldLockThreadRegistry=*/false),
310 function(function_) {
311 char bug_type[100];
312 internal_snprintf(buffer: bug_type, length: sizeof(bug_type), format: "%s-param-overlap", function);
313 scariness.Clear();
314 scariness.Scare(add_to_score: 10, reason: bug_type);
315 }
316 void Print();
317};
318
319struct ErrorStringFunctionSizeOverflow : ErrorBase {
320 const BufferedStackTrace *stack;
321 AddressDescription addr_description;
322 uptr size;
323
324 ErrorStringFunctionSizeOverflow() = default; // (*)
325 ErrorStringFunctionSizeOverflow(u32 tid, BufferedStackTrace *stack_,
326 uptr addr, uptr size_)
327 : ErrorBase(tid, 10, "negative-size-param"),
328 stack(stack_),
329 addr_description(addr, /*shouldLockThreadRegistry=*/false),
330 size(size_) {}
331 void Print();
332};
333
334struct ErrorBadParamsToAnnotateContiguousContainer : ErrorBase {
335 const BufferedStackTrace *stack;
336 uptr beg, end, old_mid, new_mid;
337
338 ErrorBadParamsToAnnotateContiguousContainer() = default; // (*)
339 // PS4: Do we want an AddressDescription for beg?
340 ErrorBadParamsToAnnotateContiguousContainer(u32 tid,
341 BufferedStackTrace *stack_,
342 uptr beg_, uptr end_,
343 uptr old_mid_, uptr new_mid_)
344 : ErrorBase(tid, 10, "bad-__sanitizer_annotate_contiguous_container"),
345 stack(stack_),
346 beg(beg_),
347 end(end_),
348 old_mid(old_mid_),
349 new_mid(new_mid_) {}
350 void Print();
351};
352
353struct ErrorBadParamsToAnnotateDoubleEndedContiguousContainer : ErrorBase {
354 const BufferedStackTrace *stack;
355 uptr storage_beg, storage_end, old_container_beg, old_container_end,
356 new_container_beg, new_container_end;
357
358 ErrorBadParamsToAnnotateDoubleEndedContiguousContainer() = default; // (*)
359 ErrorBadParamsToAnnotateDoubleEndedContiguousContainer(
360 u32 tid, BufferedStackTrace *stack_, uptr storage_beg_, uptr storage_end_,
361 uptr old_container_beg_, uptr old_container_end_, uptr new_container_beg_,
362 uptr new_container_end_)
363 : ErrorBase(tid, 10,
364 "bad-__sanitizer_annotate_double_ended_contiguous_container"),
365 stack(stack_),
366 storage_beg(storage_beg_),
367 storage_end(storage_end_),
368 old_container_beg(old_container_beg_),
369 old_container_end(old_container_end_),
370 new_container_beg(new_container_beg_),
371 new_container_end(new_container_end_) {}
372 void Print();
373};
374
375struct ErrorBadParamsToCopyContiguousContainerAnnotations : ErrorBase {
376 const BufferedStackTrace *stack;
377 uptr old_storage_beg, old_storage_end, new_storage_beg, new_storage_end;
378
379 ErrorBadParamsToCopyContiguousContainerAnnotations() = default; // (*)
380 ErrorBadParamsToCopyContiguousContainerAnnotations(
381 u32 tid, BufferedStackTrace *stack_, uptr old_storage_beg_,
382 uptr old_storage_end_, uptr new_storage_beg_, uptr new_storage_end_)
383 : ErrorBase(tid, 10,
384 "bad-__sanitizer_copy_contiguous_container_annotations"),
385 stack(stack_),
386 old_storage_beg(old_storage_beg_),
387 old_storage_end(old_storage_end_),
388 new_storage_beg(new_storage_beg_),
389 new_storage_end(new_storage_end_) {}
390 void Print();
391};
392
393struct ErrorODRViolation : ErrorBase {
394 __asan_global global1, global2;
395 u32 stack_id1, stack_id2;
396
397 ErrorODRViolation() = default; // (*)
398 ErrorODRViolation(u32 tid, const __asan_global *g1, u32 stack_id1_,
399 const __asan_global *g2, u32 stack_id2_)
400 : ErrorBase(tid, 10, "odr-violation"),
401 global1(*g1),
402 global2(*g2),
403 stack_id1(stack_id1_),
404 stack_id2(stack_id2_) {}
405 void Print();
406};
407
408struct ErrorInvalidPointerPair : ErrorBase {
409 uptr pc, bp, sp;
410 AddressDescription addr1_description;
411 AddressDescription addr2_description;
412
413 ErrorInvalidPointerPair() = default; // (*)
414 ErrorInvalidPointerPair(u32 tid, uptr pc_, uptr bp_, uptr sp_, uptr p1,
415 uptr p2)
416 : ErrorBase(tid, 10, "invalid-pointer-pair"),
417 pc(pc_),
418 bp(bp_),
419 sp(sp_),
420 addr1_description(p1, 1, /*shouldLockThreadRegistry=*/false),
421 addr2_description(p2, 1, /*shouldLockThreadRegistry=*/false) {}
422 void Print();
423};
424
425struct ErrorGeneric : ErrorBase {
426 AddressDescription addr_description;
427 uptr pc, bp, sp;
428 uptr access_size;
429 const char *bug_descr;
430 bool is_write;
431 u8 shadow_val;
432
433 ErrorGeneric() = default; // (*)
434 ErrorGeneric(u32 tid, uptr pc_, uptr bp_, uptr sp_, uptr addr, bool is_write_,
435 uptr access_size_);
436 void Print();
437};
438
439// clang-format off
440#define ASAN_FOR_EACH_ERROR_KIND(macro) \
441 macro(DeadlySignal) \
442 macro(DoubleFree) \
443 macro(NewDeleteTypeMismatch) \
444 macro(FreeSizeMismatch) \
445 macro(FreeNotMalloced) \
446 macro(AllocTypeMismatch) \
447 macro(MallocUsableSizeNotOwned) \
448 macro(SanitizerGetAllocatedSizeNotOwned) \
449 macro(CallocOverflow) \
450 macro(ReallocArrayOverflow) \
451 macro(PvallocOverflow) \
452 macro(InvalidAllocationAlignment) \
453 macro(InvalidAlignedAllocAlignment) \
454 macro(InvalidPosixMemalignAlignment) \
455 macro(AllocationSizeTooBig) \
456 macro(RssLimitExceeded) \
457 macro(OutOfMemory) \
458 macro(StringFunctionMemoryRangesOverlap) \
459 macro(StringFunctionSizeOverflow) \
460 macro(BadParamsToAnnotateContiguousContainer) \
461 macro(BadParamsToAnnotateDoubleEndedContiguousContainer) \
462 macro(BadParamsToCopyContiguousContainerAnnotations) \
463 macro(ODRViolation) \
464 macro(InvalidPointerPair) \
465 macro(Generic)
466// clang-format on
467
468#define ASAN_DEFINE_ERROR_KIND(name) kErrorKind##name,
469#define ASAN_ERROR_DESCRIPTION_MEMBER(name) Error##name name;
470#define ASAN_ERROR_DESCRIPTION_CONSTRUCTOR(name) \
471 ErrorDescription(Error##name const &e) : kind(kErrorKind##name) { \
472 internal_memcpy(&name, &e, sizeof(name)); \
473 }
474#define ASAN_ERROR_DESCRIPTION_PRINT(name) \
475 case kErrorKind##name: \
476 return name.Print();
477
478enum ErrorKind {
479 kErrorKindInvalid = 0,
480 ASAN_FOR_EACH_ERROR_KIND(ASAN_DEFINE_ERROR_KIND)
481};
482
483struct ErrorDescription {
484 ErrorKind kind;
485 // We're using a tagged union because it allows us to have a trivially
486 // copiable type and use the same structures as the public interface.
487 //
488 // We can add a wrapper around it to make it "more c++-like", but that would
489 // add a lot of code and the benefit wouldn't be that big.
490 union {
491 ErrorBase Base;
492 ASAN_FOR_EACH_ERROR_KIND(ASAN_ERROR_DESCRIPTION_MEMBER)
493 };
494
495 ErrorDescription() { internal_memset(s: this, c: 0, n: sizeof(*this)); }
496 explicit ErrorDescription(LinkerInitialized) {}
497 ASAN_FOR_EACH_ERROR_KIND(ASAN_ERROR_DESCRIPTION_CONSTRUCTOR)
498
499 bool IsValid() { return kind != kErrorKindInvalid; }
500 void Print() {
501 switch (kind) {
502 ASAN_FOR_EACH_ERROR_KIND(ASAN_ERROR_DESCRIPTION_PRINT)
503 case kErrorKindInvalid:
504 CHECK(0);
505 }
506 CHECK(0);
507 }
508};
509
510#undef ASAN_FOR_EACH_ERROR_KIND
511#undef ASAN_DEFINE_ERROR_KIND
512#undef ASAN_ERROR_DESCRIPTION_MEMBER
513#undef ASAN_ERROR_DESCRIPTION_CONSTRUCTOR
514#undef ASAN_ERROR_DESCRIPTION_PRINT
515
516} // namespace __asan
517
518#endif // ASAN_ERRORS_H
519