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.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
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, 1, &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, 1, &addr_description);
95  }
96  void Print();
97};
98
99struct 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
111struct ErrorAllocTypeMismatch : ErrorBase {
112  const BufferedStackTrace *dealloc_stack;
113  AllocType alloc_type, dealloc_type;
114  AddressDescription addr_description;
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        addr_description(addr, 1, false) {}
124  void Print();
125};
126
127struct ErrorMallocUsableSizeNotOwned : ErrorBase {
128  const BufferedStackTrace *stack;
129  AddressDescription addr_description;
130
131  ErrorMallocUsableSizeNotOwned() = default;  // (*)
132  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
139struct ErrorSanitizerGetAllocatedSizeNotOwned : ErrorBase {
140  const BufferedStackTrace *stack;
141  AddressDescription addr_description;
142
143  ErrorSanitizerGetAllocatedSizeNotOwned() = default;  // (*)
144  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
152struct ErrorCallocOverflow : ErrorBase {
153  const BufferedStackTrace *stack;
154  uptr count;
155  uptr size;
156
157  ErrorCallocOverflow() = default;  // (*)
158  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
167struct ErrorReallocArrayOverflow : ErrorBase {
168  const BufferedStackTrace *stack;
169  uptr count;
170  uptr size;
171
172  ErrorReallocArrayOverflow() = default;  // (*)
173  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
182struct ErrorPvallocOverflow : ErrorBase {
183  const BufferedStackTrace *stack;
184  uptr size;
185
186  ErrorPvallocOverflow() = default;  // (*)
187  ErrorPvallocOverflow(u32 tid, BufferedStackTrace *stack_, uptr size_)
188      : ErrorBase(tid, 10, "pvalloc-overflow"),
189        stack(stack_),
190        size(size_) {}
191  void Print();
192};
193
194struct ErrorInvalidAllocationAlignment : ErrorBase {
195  const BufferedStackTrace *stack;
196  uptr alignment;
197
198  ErrorInvalidAllocationAlignment() = default;  // (*)
199  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
207struct ErrorInvalidAlignedAllocAlignment : ErrorBase {
208  const BufferedStackTrace *stack;
209  uptr size;
210  uptr alignment;
211
212  ErrorInvalidAlignedAllocAlignment() = default;  // (*)
213  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
222struct ErrorInvalidPosixMemalignAlignment : ErrorBase {
223  const BufferedStackTrace *stack;
224  uptr alignment;
225
226  ErrorInvalidPosixMemalignAlignment() = default;  // (*)
227  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
235struct ErrorAllocationSizeTooBig : ErrorBase {
236  const BufferedStackTrace *stack;
237  uptr user_size;
238  uptr total_size;
239  uptr max_size;
240
241  ErrorAllocationSizeTooBig() = default;  // (*)
242  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
252struct ErrorRssLimitExceeded : ErrorBase {
253  const BufferedStackTrace *stack;
254
255  ErrorRssLimitExceeded() = default;  // (*)
256  ErrorRssLimitExceeded(u32 tid, BufferedStackTrace *stack_)
257      : ErrorBase(tid, 10, "rss-limit-exceeded"),
258        stack(stack_) {}
259  void Print();
260};
261
262struct ErrorOutOfMemory : ErrorBase {
263  const BufferedStackTrace *stack;
264  uptr requested_size;
265
266  ErrorOutOfMemory() = default;  // (*)
267  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
274struct 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;  // (*)
282  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
300struct ErrorStringFunctionSizeOverflow : ErrorBase {
301  const BufferedStackTrace *stack;
302  AddressDescription addr_description;
303  uptr size;
304
305  ErrorStringFunctionSizeOverflow() = default;  // (*)
306  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
315struct 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?
321  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
334struct ErrorODRViolation : ErrorBase {
335  __asan_global global1, global2;
336  u32 stack_id1, stack_id2;
337
338  ErrorODRViolation() = default;  // (*)
339  ErrorODRViolation(u32 tid, const __asan_global *g1, u32 stack_id1_,
340                    const __asan_global *g2, u32 stack_id2_)
341      : ErrorBase(tid, 10, "odr-violation"),
342        global1(*g1),
343        global2(*g2),
344        stack_id1(stack_id1_),
345        stack_id2(stack_id2_) {}
346  void Print();
347};
348
349struct ErrorInvalidPointerPair : ErrorBase {
350  uptr pc, bp, sp;
351  AddressDescription addr1_description;
352  AddressDescription addr2_description;
353
354  ErrorInvalidPointerPair() = default;  // (*)
355  ErrorInvalidPointerPair(u32 tid, uptr pc_, uptr bp_, uptr sp_, uptr p1,
356                          uptr p2)
357      : ErrorBase(tid, 10, "invalid-pointer-pair"),
358        pc(pc_),
359        bp(bp_),
360        sp(sp_),
361        addr1_description(p1, 1, /*shouldLockThreadRegistry=*/false),
362        addr2_description(p2, 1, /*shouldLockThreadRegistry=*/false) {}
363  void Print();
364};
365
366struct ErrorGeneric : ErrorBase {
367  AddressDescription addr_description;
368  uptr pc, bp, sp;
369  uptr access_size;
370  const char *bug_descr;
371  bool is_write;
372  u8 shadow_val;
373
374  ErrorGeneric() = default;  // (*)
375  ErrorGeneric(u32 tid, uptr addr, uptr pc_, uptr bp_, uptr sp_, bool is_write_,
376               uptr access_size_);
377  void Print();
378};
379
380// clang-format off
381#define ASAN_FOR_EACH_ERROR_KIND(macro)         \
382  macro(DeadlySignal)                           \
383  macro(DoubleFree)                             \
384  macro(NewDeleteTypeMismatch)                  \
385  macro(FreeNotMalloced)                        \
386  macro(AllocTypeMismatch)                      \
387  macro(MallocUsableSizeNotOwned)               \
388  macro(SanitizerGetAllocatedSizeNotOwned)      \
389  macro(CallocOverflow)                         \
390  macro(ReallocArrayOverflow)                   \
391  macro(PvallocOverflow)                        \
392  macro(InvalidAllocationAlignment)             \
393  macro(InvalidAlignedAllocAlignment)           \
394  macro(InvalidPosixMemalignAlignment)          \
395  macro(AllocationSizeTooBig)                   \
396  macro(RssLimitExceeded)                       \
397  macro(OutOfMemory)                            \
398  macro(StringFunctionMemoryRangesOverlap)      \
399  macro(StringFunctionSizeOverflow)             \
400  macro(BadParamsToAnnotateContiguousContainer) \
401  macro(ODRViolation)                           \
402  macro(InvalidPointerPair)                     \
403  macro(Generic)
404// clang-format on
405
406#define ASAN_DEFINE_ERROR_KIND(name) kErrorKind##name,
407#define ASAN_ERROR_DESCRIPTION_MEMBER(name) Error##name name;
408#define ASAN_ERROR_DESCRIPTION_CONSTRUCTOR(name)                    \
409  ErrorDescription(Error##name const &e) : kind(kErrorKind##name) { \
410    internal_memcpy(&name, &e, sizeof(name));                       \
411  }
412#define ASAN_ERROR_DESCRIPTION_PRINT(name) \
413  case kErrorKind##name:                   \
414    return name.Print();
415
416enum ErrorKind {
417  kErrorKindInvalid = 0,
418  ASAN_FOR_EACH_ERROR_KIND(ASAN_DEFINE_ERROR_KIND)
419};
420
421struct ErrorDescription {
422  ErrorKind kind;
423  // We're using a tagged union because it allows us to have a trivially
424  // copiable type and use the same structures as the public interface.
425  //
426  // We can add a wrapper around it to make it "more c++-like", but that would
427  // add a lot of code and the benefit wouldn't be that big.
428  union {
429    ErrorBase Base;
430    ASAN_FOR_EACH_ERROR_KIND(ASAN_ERROR_DESCRIPTION_MEMBER)
431  };
432
433  ErrorDescription() { internal_memset(this, 0, sizeof(*this)); }
434  explicit ErrorDescription(LinkerInitialized) {}
435  ASAN_FOR_EACH_ERROR_KIND(ASAN_ERROR_DESCRIPTION_CONSTRUCTOR)
436
437  bool IsValid() { return kind != kErrorKindInvalid; }
438  void Print() {
439    switch (kind) {
440      ASAN_FOR_EACH_ERROR_KIND(ASAN_ERROR_DESCRIPTION_PRINT)
441      case kErrorKindInvalid:
442        CHECK(0);
443    }
444    CHECK(0);
445  }
446};
447
448#undef ASAN_FOR_EACH_ERROR_KIND
449#undef ASAN_DEFINE_ERROR_KIND
450#undef ASAN_ERROR_DESCRIPTION_MEMBER
451#undef ASAN_ERROR_DESCRIPTION_CONSTRUCTOR
452#undef ASAN_ERROR_DESCRIPTION_PRINT
453
454}  // namespace __asan
455
456#endif  // ASAN_ERRORS_H
457