asan_errors.h revision 355940
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(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(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
66struct 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
80struct 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
98struct 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
110struct 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
126struct 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
138struct 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
151struct 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
166struct 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
181struct 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
193struct 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
206struct 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
221struct 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
234struct 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
251struct 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
261struct 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
273struct 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
299struct 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
314struct 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
333struct 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
348struct 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
365struct 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
415enum ErrorKind {
416  kErrorKindInvalid = 0,
417  ASAN_FOR_EACH_ERROR_KIND(ASAN_DEFINE_ERROR_KIND)
418};
419
420struct 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