xref: /llvm-project/compiler-rt/lib/asan/asan_errors.h (revision dcf0097962e4506aec59fbbd01c874527d2e061d)
1 //===-- asan_errors.h -------------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file is a part of AddressSanitizer, an address sanity checker.
11 //
12 // ASan-private header for error structures.
13 //===----------------------------------------------------------------------===//
14 #ifndef ASAN_ERRORS_H
15 #define ASAN_ERRORS_H
16 
17 #include "asan_descriptions.h"
18 #include "asan_scariness_score.h"
19 #include "sanitizer_common/sanitizer_common.h"
20 
21 namespace __asan {
22 
23 // (*) VS2013 does not implement unrestricted unions, so we need a trivial
24 // default constructor explicitly defined for each particular error.
25 
26 // None of the error classes own the stack traces mentioned in them.
27 
28 struct ErrorBase {
29   ScarinessScoreBase scariness;
30   u32 tid;
31 
32   ErrorBase() = default;  // (*)
33   explicit ErrorBase(u32 tid_) : tid(tid_) {}
34   ErrorBase(u32 tid_, int initial_score, const char *reason) : tid(tid_) {
35     scariness.Clear();
36     scariness.Scare(initial_score, reason);
37   }
38 };
39 
40 struct ErrorDeadlySignal : ErrorBase {
41   SignalContext signal;
42 
43   ErrorDeadlySignal() = default;  // (*)
44   ErrorDeadlySignal(u32 tid, const SignalContext &sig)
45       : ErrorBase(tid),
46         signal(sig) {
47     scariness.Clear();
48     if (signal.IsStackOverflow()) {
49       scariness.Scare(10, "stack-overflow");
50     } else if (!signal.is_memory_access) {
51       scariness.Scare(10, "signal");
52     } else if (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;  // (*)
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, 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;  // (*)
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, 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;  // (*)
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   HeapAddressDescription addr_description;
114   AllocType alloc_type, dealloc_type;
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     GetHeapAddressInformation(addr, 1, &addr_description);
124   };
125   void Print();
126 };
127 
128 struct ErrorMallocUsableSizeNotOwned : ErrorBase {
129   const BufferedStackTrace *stack;
130   AddressDescription addr_description;
131 
132   ErrorMallocUsableSizeNotOwned() = default;  // (*)
133   ErrorMallocUsableSizeNotOwned(u32 tid, BufferedStackTrace *stack_, uptr addr)
134       : ErrorBase(tid, 10, "bad-malloc_usable_size"),
135         stack(stack_),
136         addr_description(addr, /*shouldLockThreadRegistry=*/false) {}
137   void Print();
138 };
139 
140 struct ErrorSanitizerGetAllocatedSizeNotOwned : ErrorBase {
141   const BufferedStackTrace *stack;
142   AddressDescription addr_description;
143 
144   ErrorSanitizerGetAllocatedSizeNotOwned() = default;  // (*)
145   ErrorSanitizerGetAllocatedSizeNotOwned(u32 tid, BufferedStackTrace *stack_,
146                                          uptr addr)
147       : ErrorBase(tid, 10, "bad-__sanitizer_get_allocated_size"),
148         stack(stack_),
149         addr_description(addr, /*shouldLockThreadRegistry=*/false) {}
150   void Print();
151 };
152 
153 struct ErrorCallocOverflow : ErrorBase {
154   const BufferedStackTrace *stack;
155   uptr count;
156   uptr size;
157 
158   ErrorCallocOverflow() = default;  // (*)
159   ErrorCallocOverflow(u32 tid, BufferedStackTrace *stack_, uptr count_,
160                       uptr size_)
161       : ErrorBase(tid, 10, "calloc-overflow"),
162         stack(stack_),
163         count(count_),
164         size(size_) {}
165   void Print();
166 };
167 
168 struct ErrorPvallocOverflow : ErrorBase {
169   const BufferedStackTrace *stack;
170   uptr size;
171 
172   ErrorPvallocOverflow() = default;  // (*)
173   ErrorPvallocOverflow(u32 tid, BufferedStackTrace *stack_, uptr size_)
174       : ErrorBase(tid, 10, "pvalloc-overflow"),
175         stack(stack_),
176         size(size_) {}
177   void Print();
178 };
179 
180 struct ErrorInvalidAllocationAlignment : ErrorBase {
181   const BufferedStackTrace *stack;
182   uptr alignment;
183 
184   ErrorInvalidAllocationAlignment() = default;  // (*)
185   ErrorInvalidAllocationAlignment(u32 tid, BufferedStackTrace *stack_,
186                                   uptr alignment_)
187       : ErrorBase(tid, 10, "invalid-allocation-alignment"),
188         stack(stack_),
189         alignment(alignment_) {}
190   void Print();
191 };
192 
193 struct ErrorInvalidAlignedAllocAlignment : ErrorBase {
194   const BufferedStackTrace *stack;
195   uptr size;
196   uptr alignment;
197 
198   ErrorInvalidAlignedAllocAlignment() = default;  // (*)
199   ErrorInvalidAlignedAllocAlignment(u32 tid, BufferedStackTrace *stack_,
200                                     uptr size_, uptr alignment_)
201       : ErrorBase(tid, 10, "invalid-aligned-alloc-alignment"),
202         stack(stack_),
203         size(size_),
204         alignment(alignment_) {}
205   void Print();
206 };
207 
208 struct ErrorInvalidPosixMemalignAlignment : ErrorBase {
209   const BufferedStackTrace *stack;
210   uptr alignment;
211 
212   ErrorInvalidPosixMemalignAlignment() = default;  // (*)
213   ErrorInvalidPosixMemalignAlignment(u32 tid, BufferedStackTrace *stack_,
214                                      uptr alignment_)
215       : ErrorBase(tid, 10, "invalid-posix-memalign-alignment"),
216         stack(stack_),
217         alignment(alignment_) {}
218   void Print();
219 };
220 
221 struct ErrorAllocationSizeTooBig : ErrorBase {
222   const BufferedStackTrace *stack;
223   uptr user_size;
224   uptr total_size;
225   uptr max_size;
226 
227   ErrorAllocationSizeTooBig() = default;  // (*)
228   ErrorAllocationSizeTooBig(u32 tid, BufferedStackTrace *stack_,
229                             uptr user_size_, uptr total_size_, uptr max_size_)
230       : ErrorBase(tid, 10, "allocation-size-too-big"),
231         stack(stack_),
232         user_size(user_size_),
233         total_size(total_size_),
234         max_size(max_size_) {}
235   void Print();
236 };
237 
238 struct ErrorRssLimitExceeded : ErrorBase {
239   const BufferedStackTrace *stack;
240 
241   ErrorRssLimitExceeded() = default;  // (*)
242   ErrorRssLimitExceeded(u32 tid, BufferedStackTrace *stack_)
243       : ErrorBase(tid, 10, "rss-limit-exceeded"),
244         stack(stack_) {}
245   void Print();
246 };
247 
248 struct ErrorOutOfMemory : ErrorBase {
249   const BufferedStackTrace *stack;
250   uptr requested_size;
251 
252   ErrorOutOfMemory() = default;  // (*)
253   ErrorOutOfMemory(u32 tid, BufferedStackTrace *stack_, uptr requested_size_)
254       : ErrorBase(tid, 10, "out-of-memory"),
255         stack(stack_),
256         requested_size(requested_size_) {}
257   void Print();
258 };
259 
260 struct ErrorStringFunctionMemoryRangesOverlap : ErrorBase {
261   const BufferedStackTrace *stack;
262   uptr length1, length2;
263   AddressDescription addr1_description;
264   AddressDescription addr2_description;
265   const char *function;
266 
267   ErrorStringFunctionMemoryRangesOverlap() = default;  // (*)
268   ErrorStringFunctionMemoryRangesOverlap(u32 tid, BufferedStackTrace *stack_,
269                                          uptr addr1, uptr length1_, uptr addr2,
270                                          uptr length2_, const char *function_)
271       : ErrorBase(tid),
272         stack(stack_),
273         length1(length1_),
274         length2(length2_),
275         addr1_description(addr1, length1, /*shouldLockThreadRegistry=*/false),
276         addr2_description(addr2, length2, /*shouldLockThreadRegistry=*/false),
277         function(function_) {
278     char bug_type[100];
279     internal_snprintf(bug_type, sizeof(bug_type), "%s-param-overlap", function);
280     scariness.Clear();
281     scariness.Scare(10, bug_type);
282   }
283   void Print();
284 };
285 
286 struct ErrorStringFunctionSizeOverflow : ErrorBase {
287   const BufferedStackTrace *stack;
288   AddressDescription addr_description;
289   uptr size;
290 
291   ErrorStringFunctionSizeOverflow() = default;  // (*)
292   ErrorStringFunctionSizeOverflow(u32 tid, BufferedStackTrace *stack_,
293                                   uptr addr, uptr size_)
294       : ErrorBase(tid, 10, "negative-size-param"),
295         stack(stack_),
296         addr_description(addr, /*shouldLockThreadRegistry=*/false),
297         size(size_) {}
298   void Print();
299 };
300 
301 struct ErrorBadParamsToAnnotateContiguousContainer : ErrorBase {
302   const BufferedStackTrace *stack;
303   uptr beg, end, old_mid, new_mid;
304 
305   ErrorBadParamsToAnnotateContiguousContainer() = default;  // (*)
306   // PS4: Do we want an AddressDescription for beg?
307   ErrorBadParamsToAnnotateContiguousContainer(u32 tid,
308                                               BufferedStackTrace *stack_,
309                                               uptr beg_, uptr end_,
310                                               uptr old_mid_, uptr new_mid_)
311       : ErrorBase(tid, 10, "bad-__sanitizer_annotate_contiguous_container"),
312         stack(stack_),
313         beg(beg_),
314         end(end_),
315         old_mid(old_mid_),
316         new_mid(new_mid_) {}
317   void Print();
318 };
319 
320 struct ErrorODRViolation : ErrorBase {
321   __asan_global global1, global2;
322   u32 stack_id1, stack_id2;
323 
324   ErrorODRViolation() = default;  // (*)
325   ErrorODRViolation(u32 tid, const __asan_global *g1, u32 stack_id1_,
326                     const __asan_global *g2, u32 stack_id2_)
327       : ErrorBase(tid, 10, "odr-violation"),
328         global1(*g1),
329         global2(*g2),
330         stack_id1(stack_id1_),
331         stack_id2(stack_id2_) {}
332   void Print();
333 };
334 
335 struct ErrorInvalidPointerPair : ErrorBase {
336   uptr pc, bp, sp;
337   AddressDescription addr1_description;
338   AddressDescription addr2_description;
339 
340   ErrorInvalidPointerPair() = default;  // (*)
341   ErrorInvalidPointerPair(u32 tid, uptr pc_, uptr bp_, uptr sp_, uptr p1,
342                           uptr p2)
343       : ErrorBase(tid, 10, "invalid-pointer-pair"),
344         pc(pc_),
345         bp(bp_),
346         sp(sp_),
347         addr1_description(p1, 1, /*shouldLockThreadRegistry=*/false),
348         addr2_description(p2, 1, /*shouldLockThreadRegistry=*/false) {}
349   void Print();
350 };
351 
352 struct ErrorGeneric : ErrorBase {
353   AddressDescription addr_description;
354   uptr pc, bp, sp;
355   uptr access_size;
356   const char *bug_descr;
357   bool is_write;
358   u8 shadow_val;
359 
360   ErrorGeneric() = default;  // (*)
361   ErrorGeneric(u32 tid, uptr addr, uptr pc_, uptr bp_, uptr sp_, bool is_write_,
362                uptr access_size_);
363   void Print();
364 };
365 
366 // clang-format off
367 #define ASAN_FOR_EACH_ERROR_KIND(macro)         \
368   macro(DeadlySignal)                           \
369   macro(DoubleFree)                             \
370   macro(NewDeleteTypeMismatch)                  \
371   macro(FreeNotMalloced)                        \
372   macro(AllocTypeMismatch)                      \
373   macro(MallocUsableSizeNotOwned)               \
374   macro(SanitizerGetAllocatedSizeNotOwned)      \
375   macro(CallocOverflow)                         \
376   macro(PvallocOverflow)                        \
377   macro(InvalidAllocationAlignment)             \
378   macro(InvalidAlignedAllocAlignment)           \
379   macro(InvalidPosixMemalignAlignment)          \
380   macro(AllocationSizeTooBig)                   \
381   macro(RssLimitExceeded)                       \
382   macro(OutOfMemory)                            \
383   macro(StringFunctionMemoryRangesOverlap)      \
384   macro(StringFunctionSizeOverflow)             \
385   macro(BadParamsToAnnotateContiguousContainer) \
386   macro(ODRViolation)                           \
387   macro(InvalidPointerPair)                     \
388   macro(Generic)
389 // clang-format on
390 
391 #define ASAN_DEFINE_ERROR_KIND(name) kErrorKind##name,
392 #define ASAN_ERROR_DESCRIPTION_MEMBER(name) Error##name name;
393 #define ASAN_ERROR_DESCRIPTION_CONSTRUCTOR(name) \
394   ErrorDescription(Error##name const &e) : kind(kErrorKind##name), name(e) {}
395 #define ASAN_ERROR_DESCRIPTION_PRINT(name) \
396   case kErrorKind##name:                   \
397     return name.Print();
398 
399 enum ErrorKind {
400   kErrorKindInvalid = 0,
401   ASAN_FOR_EACH_ERROR_KIND(ASAN_DEFINE_ERROR_KIND)
402 };
403 
404 struct ErrorDescription {
405   ErrorKind kind;
406   // We're using a tagged union because it allows us to have a trivially
407   // copiable type and use the same structures as the public interface.
408   //
409   // We can add a wrapper around it to make it "more c++-like", but that would
410   // add a lot of code and the benefit wouldn't be that big.
411   union {
412     ErrorBase Base;
413     ASAN_FOR_EACH_ERROR_KIND(ASAN_ERROR_DESCRIPTION_MEMBER)
414   };
415 
416   ErrorDescription() { internal_memset(this, 0, sizeof(*this)); }
417   ASAN_FOR_EACH_ERROR_KIND(ASAN_ERROR_DESCRIPTION_CONSTRUCTOR)
418 
419   bool IsValid() { return kind != kErrorKindInvalid; }
420   void Print() {
421     switch (kind) {
422       ASAN_FOR_EACH_ERROR_KIND(ASAN_ERROR_DESCRIPTION_PRINT)
423       case kErrorKindInvalid:
424         CHECK(0);
425     }
426     CHECK(0);
427   }
428 };
429 
430 #undef ASAN_FOR_EACH_ERROR_KIND
431 #undef ASAN_DEFINE_ERROR_KIND
432 #undef ASAN_ERROR_DESCRIPTION_MEMBER
433 #undef ASAN_ERROR_DESCRIPTION_CONSTRUCTOR
434 #undef ASAN_ERROR_DESCRIPTION_PRINT
435 
436 }  // namespace __asan
437 
438 #endif  // ASAN_ERRORS_H
439