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