1//===-- asan_descriptions.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 asan_descriptions.cpp.
12// TODO(filcab): Most struct definitions should move to the interface headers.
13//===----------------------------------------------------------------------===//
14#ifndef ASAN_DESCRIPTIONS_H
15#define ASAN_DESCRIPTIONS_H
16
17#include "asan_allocator.h"
18#include "asan_thread.h"
19#include "sanitizer_common/sanitizer_common.h"
20#include "sanitizer_common/sanitizer_report_decorator.h"
21
22namespace __asan {
23
24void DescribeThread(AsanThreadContext *context);
25static inline void DescribeThread(AsanThread *t) {
26  if (t) DescribeThread(t->context());
27}
28
29class AsanThreadIdAndName {
30 public:
31  explicit AsanThreadIdAndName(AsanThreadContext *t);
32  explicit AsanThreadIdAndName(u32 tid);
33
34  // Contains "T%tid (%name)" or "T%tid" if the name is empty.
35  const char *c_str() const { return &name[0]; }
36
37 private:
38  void Init(u32 tid, const char *tname);
39
40  char name[128];
41};
42
43class Decorator : public __sanitizer::SanitizerCommonDecorator {
44 public:
45  Decorator() : SanitizerCommonDecorator() {}
46  const char *Access() { return Blue(); }
47  const char *Location() { return Green(); }
48  const char *Allocation() { return Magenta(); }
49
50  const char *ShadowByte(u8 byte) {
51    switch (byte) {
52      case kAsanHeapLeftRedzoneMagic:
53      case kAsanArrayCookieMagic:
54        return Red();
55      case kAsanHeapFreeMagic:
56        return Magenta();
57      case kAsanStackLeftRedzoneMagic:
58      case kAsanStackMidRedzoneMagic:
59      case kAsanStackRightRedzoneMagic:
60        return Red();
61      case kAsanStackAfterReturnMagic:
62        return Magenta();
63      case kAsanInitializationOrderMagic:
64        return Cyan();
65      case kAsanUserPoisonedMemoryMagic:
66      case kAsanContiguousContainerOOBMagic:
67      case kAsanAllocaLeftMagic:
68      case kAsanAllocaRightMagic:
69        return Blue();
70      case kAsanStackUseAfterScopeMagic:
71        return Magenta();
72      case kAsanGlobalRedzoneMagic:
73        return Red();
74      case kAsanInternalHeapMagic:
75        return Yellow();
76      case kAsanIntraObjectRedzone:
77        return Yellow();
78      default:
79        return Default();
80    }
81  }
82};
83
84enum ShadowKind : u8 {
85  kShadowKindLow,
86  kShadowKindGap,
87  kShadowKindHigh,
88};
89static const char *const ShadowNames[] = {"low shadow", "shadow gap",
90                                          "high shadow"};
91
92struct ShadowAddressDescription {
93  uptr addr;
94  ShadowKind kind;
95  u8 shadow_byte;
96
97  void Print() const;
98};
99
100bool GetShadowAddressInformation(uptr addr, ShadowAddressDescription *descr);
101bool DescribeAddressIfShadow(uptr addr);
102
103enum AccessType {
104  kAccessTypeLeft,
105  kAccessTypeRight,
106  kAccessTypeInside,
107  kAccessTypeUnknown,  // This means we have an AddressSanitizer bug!
108};
109
110struct ChunkAccess {
111  uptr bad_addr;
112  sptr offset;
113  uptr chunk_begin;
114  uptr chunk_size;
115  u32 user_requested_alignment : 12;
116  u32 access_type : 2;
117  u32 alloc_type : 2;
118};
119
120struct HeapAddressDescription {
121  uptr addr;
122  uptr alloc_tid;
123  uptr free_tid;
124  u32 alloc_stack_id;
125  u32 free_stack_id;
126  ChunkAccess chunk_access;
127
128  void Print() const;
129};
130
131bool GetHeapAddressInformation(uptr addr, uptr access_size,
132                               HeapAddressDescription *descr);
133bool DescribeAddressIfHeap(uptr addr, uptr access_size = 1);
134
135struct StackAddressDescription {
136  uptr addr;
137  uptr tid;
138  uptr offset;
139  uptr frame_pc;
140  uptr access_size;
141  const char *frame_descr;
142
143  void Print() const;
144};
145
146bool GetStackAddressInformation(uptr addr, uptr access_size,
147                                StackAddressDescription *descr);
148
149struct WildAddressDescription {
150  uptr addr;
151  uptr access_size;
152
153  void Print() const;
154};
155
156struct GlobalAddressDescription {
157  uptr addr;
158  // Assume address is close to at most four globals.
159  static const int kMaxGlobals = 4;
160  __asan_global globals[kMaxGlobals];
161  u32 reg_sites[kMaxGlobals];
162  uptr access_size;
163  u8 size;
164
165  void Print(const char *bug_type = "") const;
166
167  // Returns true when this descriptions points inside the same global variable
168  // as other. Descriptions can have different address within the variable
169  bool PointsInsideTheSameVariable(const GlobalAddressDescription &other) const;
170};
171
172bool GetGlobalAddressInformation(uptr addr, uptr access_size,
173                                 GlobalAddressDescription *descr);
174bool DescribeAddressIfGlobal(uptr addr, uptr access_size, const char *bug_type);
175
176// General function to describe an address. Will try to describe the address as
177// a shadow, global (variable), stack, or heap address.
178// bug_type is optional and is used for checking if we're reporting an
179// initialization-order-fiasco
180// The proper access_size should be passed for stack, global, and heap
181// addresses. Defaults to 1.
182// Each of the *AddressDescription functions has its own Print() member, which
183// may take access_size and bug_type parameters if needed.
184void PrintAddressDescription(uptr addr, uptr access_size = 1,
185                             const char *bug_type = "");
186
187enum AddressKind {
188  kAddressKindWild,
189  kAddressKindShadow,
190  kAddressKindHeap,
191  kAddressKindStack,
192  kAddressKindGlobal,
193};
194
195class AddressDescription {
196  struct AddressDescriptionData {
197    AddressKind kind;
198    union {
199      ShadowAddressDescription shadow;
200      HeapAddressDescription heap;
201      StackAddressDescription stack;
202      GlobalAddressDescription global;
203      WildAddressDescription wild;
204    };
205  };
206
207  AddressDescriptionData data;
208
209 public:
210  AddressDescription() = default;
211  // shouldLockThreadRegistry allows us to skip locking if we're sure we already
212  // have done it.
213  explicit AddressDescription(uptr addr, bool shouldLockThreadRegistry = true)
214      : AddressDescription(addr, 1, shouldLockThreadRegistry) {}
215  AddressDescription(uptr addr, uptr access_size,
216                     bool shouldLockThreadRegistry = true);
217
218  uptr Address() const {
219    switch (data.kind) {
220      case kAddressKindWild:
221        return data.wild.addr;
222      case kAddressKindShadow:
223        return data.shadow.addr;
224      case kAddressKindHeap:
225        return data.heap.addr;
226      case kAddressKindStack:
227        return data.stack.addr;
228      case kAddressKindGlobal:
229        return data.global.addr;
230    }
231    UNREACHABLE("AddressInformation kind is invalid");
232  }
233  void Print(const char *bug_descr = nullptr) const {
234    switch (data.kind) {
235      case kAddressKindWild:
236        data.wild.Print();
237        return;
238      case kAddressKindShadow:
239        return data.shadow.Print();
240      case kAddressKindHeap:
241        return data.heap.Print();
242      case kAddressKindStack:
243        return data.stack.Print();
244      case kAddressKindGlobal:
245        // initialization-order-fiasco has a special Print()
246        return data.global.Print(bug_descr);
247    }
248    UNREACHABLE("AddressInformation kind is invalid");
249  }
250
251  void StoreTo(AddressDescriptionData *dst) const { *dst = data; }
252
253  const ShadowAddressDescription *AsShadow() const {
254    return data.kind == kAddressKindShadow ? &data.shadow : nullptr;
255  }
256  const HeapAddressDescription *AsHeap() const {
257    return data.kind == kAddressKindHeap ? &data.heap : nullptr;
258  }
259  const StackAddressDescription *AsStack() const {
260    return data.kind == kAddressKindStack ? &data.stack : nullptr;
261  }
262  const GlobalAddressDescription *AsGlobal() const {
263    return data.kind == kAddressKindGlobal ? &data.global : nullptr;
264  }
265};
266
267}  // namespace __asan
268
269#endif  // ASAN_DESCRIPTIONS_H
270