1311120Sdim//===-- asan_descriptions.h -------------------------------------*- C++ -*-===//
2311120Sdim//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6311120Sdim//
7311120Sdim//===----------------------------------------------------------------------===//
8311120Sdim//
9311120Sdim// This file is a part of AddressSanitizer, an address sanity checker.
10311120Sdim//
11360784Sdim// ASan-private header for asan_descriptions.cpp.
12311120Sdim// TODO(filcab): Most struct definitions should move to the interface headers.
13311120Sdim//===----------------------------------------------------------------------===//
14311120Sdim#ifndef ASAN_DESCRIPTIONS_H
15311120Sdim#define ASAN_DESCRIPTIONS_H
16311120Sdim
17311120Sdim#include "asan_allocator.h"
18311120Sdim#include "asan_thread.h"
19311120Sdim#include "sanitizer_common/sanitizer_common.h"
20311120Sdim#include "sanitizer_common/sanitizer_report_decorator.h"
21311120Sdim
22311120Sdimnamespace __asan {
23311120Sdim
24311120Sdimvoid DescribeThread(AsanThreadContext *context);
25311120Sdimstatic inline void DescribeThread(AsanThread *t) {
26311120Sdim  if (t) DescribeThread(t->context());
27311120Sdim}
28311120Sdim
29341825Sdimclass AsanThreadIdAndName {
30341825Sdim public:
31341825Sdim  explicit AsanThreadIdAndName(AsanThreadContext *t);
32341825Sdim  explicit AsanThreadIdAndName(u32 tid);
33341825Sdim
34341825Sdim  // Contains "T%tid (%name)" or "T%tid" if the name is empty.
35341825Sdim  const char *c_str() const { return &name[0]; }
36341825Sdim
37341825Sdim private:
38341825Sdim  void Init(u32 tid, const char *tname);
39341825Sdim
40341825Sdim  char name[128];
41341825Sdim};
42341825Sdim
43311120Sdimclass Decorator : public __sanitizer::SanitizerCommonDecorator {
44311120Sdim public:
45311120Sdim  Decorator() : SanitizerCommonDecorator() {}
46311120Sdim  const char *Access() { return Blue(); }
47311120Sdim  const char *Location() { return Green(); }
48311120Sdim  const char *Allocation() { return Magenta(); }
49311120Sdim
50311120Sdim  const char *ShadowByte(u8 byte) {
51311120Sdim    switch (byte) {
52311120Sdim      case kAsanHeapLeftRedzoneMagic:
53311120Sdim      case kAsanArrayCookieMagic:
54311120Sdim        return Red();
55311120Sdim      case kAsanHeapFreeMagic:
56311120Sdim        return Magenta();
57311120Sdim      case kAsanStackLeftRedzoneMagic:
58311120Sdim      case kAsanStackMidRedzoneMagic:
59311120Sdim      case kAsanStackRightRedzoneMagic:
60311120Sdim        return Red();
61311120Sdim      case kAsanStackAfterReturnMagic:
62311120Sdim        return Magenta();
63311120Sdim      case kAsanInitializationOrderMagic:
64311120Sdim        return Cyan();
65311120Sdim      case kAsanUserPoisonedMemoryMagic:
66311120Sdim      case kAsanContiguousContainerOOBMagic:
67311120Sdim      case kAsanAllocaLeftMagic:
68311120Sdim      case kAsanAllocaRightMagic:
69311120Sdim        return Blue();
70311120Sdim      case kAsanStackUseAfterScopeMagic:
71311120Sdim        return Magenta();
72311120Sdim      case kAsanGlobalRedzoneMagic:
73311120Sdim        return Red();
74311120Sdim      case kAsanInternalHeapMagic:
75311120Sdim        return Yellow();
76311120Sdim      case kAsanIntraObjectRedzone:
77311120Sdim        return Yellow();
78311120Sdim      default:
79311120Sdim        return Default();
80311120Sdim    }
81311120Sdim  }
82311120Sdim};
83311120Sdim
84311120Sdimenum ShadowKind : u8 {
85311120Sdim  kShadowKindLow,
86311120Sdim  kShadowKindGap,
87311120Sdim  kShadowKindHigh,
88311120Sdim};
89311120Sdimstatic const char *const ShadowNames[] = {"low shadow", "shadow gap",
90311120Sdim                                          "high shadow"};
91311120Sdim
92311120Sdimstruct ShadowAddressDescription {
93311120Sdim  uptr addr;
94311120Sdim  ShadowKind kind;
95311120Sdim  u8 shadow_byte;
96311120Sdim
97311120Sdim  void Print() const;
98311120Sdim};
99311120Sdim
100311120Sdimbool GetShadowAddressInformation(uptr addr, ShadowAddressDescription *descr);
101311120Sdimbool DescribeAddressIfShadow(uptr addr);
102311120Sdim
103311120Sdimenum AccessType {
104311120Sdim  kAccessTypeLeft,
105311120Sdim  kAccessTypeRight,
106311120Sdim  kAccessTypeInside,
107311120Sdim  kAccessTypeUnknown,  // This means we have an AddressSanitizer bug!
108311120Sdim};
109311120Sdim
110311120Sdimstruct ChunkAccess {
111311120Sdim  uptr bad_addr;
112311120Sdim  sptr offset;
113311120Sdim  uptr chunk_begin;
114311120Sdim  uptr chunk_size;
115327952Sdim  u32 user_requested_alignment : 12;
116311120Sdim  u32 access_type : 2;
117311120Sdim  u32 alloc_type : 2;
118311120Sdim};
119311120Sdim
120311120Sdimstruct HeapAddressDescription {
121311120Sdim  uptr addr;
122311120Sdim  uptr alloc_tid;
123311120Sdim  uptr free_tid;
124311120Sdim  u32 alloc_stack_id;
125311120Sdim  u32 free_stack_id;
126311120Sdim  ChunkAccess chunk_access;
127311120Sdim
128311120Sdim  void Print() const;
129311120Sdim};
130311120Sdim
131311120Sdimbool GetHeapAddressInformation(uptr addr, uptr access_size,
132311120Sdim                               HeapAddressDescription *descr);
133311120Sdimbool DescribeAddressIfHeap(uptr addr, uptr access_size = 1);
134311120Sdim
135311120Sdimstruct StackAddressDescription {
136311120Sdim  uptr addr;
137311120Sdim  uptr tid;
138311120Sdim  uptr offset;
139311120Sdim  uptr frame_pc;
140311120Sdim  uptr access_size;
141311120Sdim  const char *frame_descr;
142311120Sdim
143311120Sdim  void Print() const;
144311120Sdim};
145311120Sdim
146311120Sdimbool GetStackAddressInformation(uptr addr, uptr access_size,
147311120Sdim                                StackAddressDescription *descr);
148311120Sdim
149311120Sdimstruct GlobalAddressDescription {
150311120Sdim  uptr addr;
151311120Sdim  // Assume address is close to at most four globals.
152311120Sdim  static const int kMaxGlobals = 4;
153311120Sdim  __asan_global globals[kMaxGlobals];
154311120Sdim  u32 reg_sites[kMaxGlobals];
155311120Sdim  uptr access_size;
156311120Sdim  u8 size;
157311120Sdim
158311120Sdim  void Print(const char *bug_type = "") const;
159327952Sdim
160327952Sdim  // Returns true when this descriptions points inside the same global variable
161327952Sdim  // as other. Descriptions can have different address within the variable
162327952Sdim  bool PointsInsideTheSameVariable(const GlobalAddressDescription &other) const;
163311120Sdim};
164311120Sdim
165311120Sdimbool GetGlobalAddressInformation(uptr addr, uptr access_size,
166311120Sdim                                 GlobalAddressDescription *descr);
167311120Sdimbool DescribeAddressIfGlobal(uptr addr, uptr access_size, const char *bug_type);
168311120Sdim
169311120Sdim// General function to describe an address. Will try to describe the address as
170311120Sdim// a shadow, global (variable), stack, or heap address.
171311120Sdim// bug_type is optional and is used for checking if we're reporting an
172311120Sdim// initialization-order-fiasco
173311120Sdim// The proper access_size should be passed for stack, global, and heap
174311120Sdim// addresses. Defaults to 1.
175311120Sdim// Each of the *AddressDescription functions has its own Print() member, which
176311120Sdim// may take access_size and bug_type parameters if needed.
177311120Sdimvoid PrintAddressDescription(uptr addr, uptr access_size = 1,
178311120Sdim                             const char *bug_type = "");
179311120Sdim
180311120Sdimenum AddressKind {
181311120Sdim  kAddressKindWild,
182311120Sdim  kAddressKindShadow,
183311120Sdim  kAddressKindHeap,
184311120Sdim  kAddressKindStack,
185311120Sdim  kAddressKindGlobal,
186311120Sdim};
187311120Sdim
188311120Sdimclass AddressDescription {
189311120Sdim  struct AddressDescriptionData {
190311120Sdim    AddressKind kind;
191311120Sdim    union {
192311120Sdim      ShadowAddressDescription shadow;
193311120Sdim      HeapAddressDescription heap;
194311120Sdim      StackAddressDescription stack;
195311120Sdim      GlobalAddressDescription global;
196311120Sdim      uptr addr;
197311120Sdim    };
198311120Sdim  };
199311120Sdim
200311120Sdim  AddressDescriptionData data;
201311120Sdim
202311120Sdim public:
203311120Sdim  AddressDescription() = default;
204311120Sdim  // shouldLockThreadRegistry allows us to skip locking if we're sure we already
205311120Sdim  // have done it.
206360784Sdim  explicit AddressDescription(uptr addr, bool shouldLockThreadRegistry = true)
207311120Sdim      : AddressDescription(addr, 1, shouldLockThreadRegistry) {}
208311120Sdim  AddressDescription(uptr addr, uptr access_size,
209311120Sdim                     bool shouldLockThreadRegistry = true);
210311120Sdim
211311120Sdim  uptr Address() const {
212311120Sdim    switch (data.kind) {
213311120Sdim      case kAddressKindWild:
214311120Sdim        return data.addr;
215311120Sdim      case kAddressKindShadow:
216311120Sdim        return data.shadow.addr;
217311120Sdim      case kAddressKindHeap:
218311120Sdim        return data.heap.addr;
219311120Sdim      case kAddressKindStack:
220311120Sdim        return data.stack.addr;
221311120Sdim      case kAddressKindGlobal:
222311120Sdim        return data.global.addr;
223311120Sdim    }
224311120Sdim    UNREACHABLE("AddressInformation kind is invalid");
225311120Sdim  }
226311120Sdim  void Print(const char *bug_descr = nullptr) const {
227311120Sdim    switch (data.kind) {
228311120Sdim      case kAddressKindWild:
229311120Sdim        Printf("Address %p is a wild pointer.\n", data.addr);
230311120Sdim        return;
231311120Sdim      case kAddressKindShadow:
232311120Sdim        return data.shadow.Print();
233311120Sdim      case kAddressKindHeap:
234311120Sdim        return data.heap.Print();
235311120Sdim      case kAddressKindStack:
236311120Sdim        return data.stack.Print();
237311120Sdim      case kAddressKindGlobal:
238311120Sdim        // initialization-order-fiasco has a special Print()
239311120Sdim        return data.global.Print(bug_descr);
240311120Sdim    }
241311120Sdim    UNREACHABLE("AddressInformation kind is invalid");
242311120Sdim  }
243311120Sdim
244311120Sdim  void StoreTo(AddressDescriptionData *dst) const { *dst = data; }
245311120Sdim
246311120Sdim  const ShadowAddressDescription *AsShadow() const {
247311120Sdim    return data.kind == kAddressKindShadow ? &data.shadow : nullptr;
248311120Sdim  }
249311120Sdim  const HeapAddressDescription *AsHeap() const {
250311120Sdim    return data.kind == kAddressKindHeap ? &data.heap : nullptr;
251311120Sdim  }
252311120Sdim  const StackAddressDescription *AsStack() const {
253311120Sdim    return data.kind == kAddressKindStack ? &data.stack : nullptr;
254311120Sdim  }
255311120Sdim  const GlobalAddressDescription *AsGlobal() const {
256311120Sdim    return data.kind == kAddressKindGlobal ? &data.global : nullptr;
257311120Sdim  }
258311120Sdim};
259311120Sdim
260311120Sdim}  // namespace __asan
261311120Sdim
262311120Sdim#endif  // ASAN_DESCRIPTIONS_H
263