xref: /freebsd/contrib/llvm-project/compiler-rt/lib/asan/asan_errors.h (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
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;  // (*)
ErrorBaseErrorBase32   explicit ErrorBase(u32 tid_) : tid(tid_) {}
ErrorBaseErrorBase33   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;  // (*)
ErrorDeadlySignalErrorDeadlySignal43   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.is_true_faulting_addr &&
52                signal.addr < GetPageSizeCached()) {
53       scariness.Scare(10, "null-deref");
54     } else if (signal.addr == signal.pc) {
55       scariness.Scare(60, "wild-jump");
56     } else if (signal.write_flag == SignalContext::Write) {
57       scariness.Scare(30, "wild-addr-write");
58     } else if (signal.write_flag == SignalContext::Read) {
59       scariness.Scare(20, "wild-addr-read");
60     } else {
61       scariness.Scare(25, "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;  // (*)
ErrorDoubleFreeErrorDoubleFree72   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, 1, &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;  // (*)
ErrorNewDeleteTypeMismatchErrorNewDeleteTypeMismatch88   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, 1, &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;  // (*)
ErrorFreeNotMallocedErrorFreeNotMalloced104   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;  // (*)
ErrorAllocTypeMismatchErrorAllocTypeMismatch117   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;  // (*)
ErrorMallocUsableSizeNotOwnedErrorMallocUsableSizeNotOwned132   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;  // (*)
ErrorSanitizerGetAllocatedSizeNotOwnedErrorSanitizerGetAllocatedSizeNotOwned144   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;  // (*)
ErrorCallocOverflowErrorCallocOverflow158   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;  // (*)
ErrorReallocArrayOverflowErrorReallocArrayOverflow173   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;  // (*)
ErrorPvallocOverflowErrorPvallocOverflow187   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;  // (*)
ErrorInvalidAllocationAlignmentErrorInvalidAllocationAlignment199   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;  // (*)
ErrorInvalidAlignedAllocAlignmentErrorInvalidAlignedAllocAlignment213   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;  // (*)
ErrorInvalidPosixMemalignAlignmentErrorInvalidPosixMemalignAlignment227   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;  // (*)
ErrorAllocationSizeTooBigErrorAllocationSizeTooBig242   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 ErrorRssLimitExceeded : ErrorBase {
253   const BufferedStackTrace *stack;
254 
255   ErrorRssLimitExceeded() = default;  // (*)
ErrorRssLimitExceededErrorRssLimitExceeded256   ErrorRssLimitExceeded(u32 tid, BufferedStackTrace *stack_)
257       : ErrorBase(tid, 10, "rss-limit-exceeded"),
258         stack(stack_) {}
259   void Print();
260 };
261 
262 struct ErrorOutOfMemory : ErrorBase {
263   const BufferedStackTrace *stack;
264   uptr requested_size;
265 
266   ErrorOutOfMemory() = default;  // (*)
ErrorOutOfMemoryErrorOutOfMemory267   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;  // (*)
ErrorStringFunctionMemoryRangesOverlapErrorStringFunctionMemoryRangesOverlap282   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(bug_type, sizeof(bug_type), "%s-param-overlap", function);
294     scariness.Clear();
295     scariness.Scare(10, 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;  // (*)
ErrorStringFunctionSizeOverflowErrorStringFunctionSizeOverflow306   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?
ErrorBadParamsToAnnotateContiguousContainerErrorBadParamsToAnnotateContiguousContainer321   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;  // (*)
ErrorBadParamsToAnnotateDoubleEndedContiguousContainerErrorBadParamsToAnnotateDoubleEndedContiguousContainer340   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;  // (*)
ErrorODRViolationErrorODRViolation361   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;  // (*)
ErrorInvalidPointerPairErrorInvalidPointerPair377   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(RssLimitExceeded)                                  \
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 
ErrorDescriptionErrorDescription456   ErrorDescription() { internal_memset(this, 0, sizeof(*this)); }
ErrorDescriptionErrorDescription457   explicit ErrorDescription(LinkerInitialized) {}
ASAN_FOR_EACH_ERROR_KINDErrorDescription458   ASAN_FOR_EACH_ERROR_KIND(ASAN_ERROR_DESCRIPTION_CONSTRUCTOR)
459 
460   bool IsValid() { return kind != kErrorKindInvalid; }
PrintErrorDescription461   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