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 GlobalAddressDescription {
150  uptr addr;
151  // Assume address is close to at most four globals.
152  static const int kMaxGlobals = 4;
153  __asan_global globals[kMaxGlobals];
154  u32 reg_sites[kMaxGlobals];
155  uptr access_size;
156  u8 size;
157
158  void Print(const char *bug_type = "") const;
159
160  // Returns true when this descriptions points inside the same global variable
161  // as other. Descriptions can have different address within the variable
162  bool PointsInsideTheSameVariable(const GlobalAddressDescription &other) const;
163};
164
165bool GetGlobalAddressInformation(uptr addr, uptr access_size,
166                                 GlobalAddressDescription *descr);
167bool DescribeAddressIfGlobal(uptr addr, uptr access_size, const char *bug_type);
168
169// General function to describe an address. Will try to describe the address as
170// a shadow, global (variable), stack, or heap address.
171// bug_type is optional and is used for checking if we're reporting an
172// initialization-order-fiasco
173// The proper access_size should be passed for stack, global, and heap
174// addresses. Defaults to 1.
175// Each of the *AddressDescription functions has its own Print() member, which
176// may take access_size and bug_type parameters if needed.
177void PrintAddressDescription(uptr addr, uptr access_size = 1,
178                             const char *bug_type = "");
179
180enum AddressKind {
181  kAddressKindWild,
182  kAddressKindShadow,
183  kAddressKindHeap,
184  kAddressKindStack,
185  kAddressKindGlobal,
186};
187
188class AddressDescription {
189  struct AddressDescriptionData {
190    AddressKind kind;
191    union {
192      ShadowAddressDescription shadow;
193      HeapAddressDescription heap;
194      StackAddressDescription stack;
195      GlobalAddressDescription global;
196      uptr addr;
197    };
198  };
199
200  AddressDescriptionData data;
201
202 public:
203  AddressDescription() = default;
204  // shouldLockThreadRegistry allows us to skip locking if we're sure we already
205  // have done it.
206  explicit AddressDescription(uptr addr, bool shouldLockThreadRegistry = true)
207      : AddressDescription(addr, 1, shouldLockThreadRegistry) {}
208  AddressDescription(uptr addr, uptr access_size,
209                     bool shouldLockThreadRegistry = true);
210
211  uptr Address() const {
212    switch (data.kind) {
213      case kAddressKindWild:
214        return data.addr;
215      case kAddressKindShadow:
216        return data.shadow.addr;
217      case kAddressKindHeap:
218        return data.heap.addr;
219      case kAddressKindStack:
220        return data.stack.addr;
221      case kAddressKindGlobal:
222        return data.global.addr;
223    }
224    UNREACHABLE("AddressInformation kind is invalid");
225  }
226  void Print(const char *bug_descr = nullptr) const {
227    switch (data.kind) {
228      case kAddressKindWild:
229        Printf("Address %p is a wild pointer.\n", data.addr);
230        return;
231      case kAddressKindShadow:
232        return data.shadow.Print();
233      case kAddressKindHeap:
234        return data.heap.Print();
235      case kAddressKindStack:
236        return data.stack.Print();
237      case kAddressKindGlobal:
238        // initialization-order-fiasco has a special Print()
239        return data.global.Print(bug_descr);
240    }
241    UNREACHABLE("AddressInformation kind is invalid");
242  }
243
244  void StoreTo(AddressDescriptionData *dst) const { *dst = data; }
245
246  const ShadowAddressDescription *AsShadow() const {
247    return data.kind == kAddressKindShadow ? &data.shadow : nullptr;
248  }
249  const HeapAddressDescription *AsHeap() const {
250    return data.kind == kAddressKindHeap ? &data.heap : nullptr;
251  }
252  const StackAddressDescription *AsStack() const {
253    return data.kind == kAddressKindStack ? &data.stack : nullptr;
254  }
255  const GlobalAddressDescription *AsGlobal() const {
256    return data.kind == kAddressKindGlobal ? &data.global : nullptr;
257  }
258};
259
260}  // namespace __asan
261
262#endif  // ASAN_DESCRIPTIONS_H
263