annotate compiler-rt/lib/gwp_asan/common.h @ 236:c4bab56944e8 llvm-original

LLVM 16
author kono
date Wed, 09 Nov 2022 17:45:10 +0900
parents 79ff65ed7e25
children 1f2b6ac9f198
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
150
anatofuz
parents:
diff changeset
1 //===-- common.h ------------------------------------------------*- C++ -*-===//
anatofuz
parents:
diff changeset
2 //
anatofuz
parents:
diff changeset
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
anatofuz
parents:
diff changeset
4 // See https://llvm.org/LICENSE.txt for license information.
anatofuz
parents:
diff changeset
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
anatofuz
parents:
diff changeset
6 //
anatofuz
parents:
diff changeset
7 //===----------------------------------------------------------------------===//
anatofuz
parents:
diff changeset
8
anatofuz
parents:
diff changeset
9 // This file contains code that is common between the crash handler and the
anatofuz
parents:
diff changeset
10 // GuardedPoolAllocator.
anatofuz
parents:
diff changeset
11
anatofuz
parents:
diff changeset
12 #ifndef GWP_ASAN_COMMON_H_
anatofuz
parents:
diff changeset
13 #define GWP_ASAN_COMMON_H_
anatofuz
parents:
diff changeset
14
anatofuz
parents:
diff changeset
15 #include "gwp_asan/definitions.h"
anatofuz
parents:
diff changeset
16 #include "gwp_asan/options.h"
anatofuz
parents:
diff changeset
17
anatofuz
parents:
diff changeset
18 #include <stddef.h>
anatofuz
parents:
diff changeset
19 #include <stdint.h>
anatofuz
parents:
diff changeset
20
anatofuz
parents:
diff changeset
21 namespace gwp_asan {
236
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
22
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
23 // Magic header that resides in the AllocatorState so that GWP-ASan bugreports
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
24 // can be understood by tools at different versions. Out-of-process crash
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
25 // handlers, like crashpad on Fuchsia, take the raw contents of the
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
26 // AllocationMetatada array and the AllocatorState, and shove them into the
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
27 // minidump. Online unpacking of these structs needs to know from which version
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
28 // of GWP-ASan it's extracting the information, as the structures are not
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
29 // stable.
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
30 struct AllocatorVersionMagic {
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
31 // The values are copied into the structure at runtime, during
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
32 // `GuardedPoolAllocator::init()` so that GWP-ASan remains completely in the
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
33 // `.bss` segment.
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
34 static constexpr uint8_t kAllocatorVersionMagic[4] = {'A', 'S', 'A', 'N'};
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
35 uint8_t Magic[4] = {};
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
36 // Update the version number when the AllocatorState or AllocationMetadata
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
37 // change.
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
38 static constexpr uint16_t kAllocatorVersion = 1;
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
39 uint16_t Version = 0;
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
40 uint16_t Reserved = 0;
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
41 };
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
42
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
43 enum class Error : uint8_t {
150
anatofuz
parents:
diff changeset
44 UNKNOWN,
anatofuz
parents:
diff changeset
45 USE_AFTER_FREE,
anatofuz
parents:
diff changeset
46 DOUBLE_FREE,
anatofuz
parents:
diff changeset
47 INVALID_FREE,
anatofuz
parents:
diff changeset
48 BUFFER_OVERFLOW,
anatofuz
parents:
diff changeset
49 BUFFER_UNDERFLOW
anatofuz
parents:
diff changeset
50 };
anatofuz
parents:
diff changeset
51
anatofuz
parents:
diff changeset
52 const char *ErrorToString(const Error &E);
anatofuz
parents:
diff changeset
53
anatofuz
parents:
diff changeset
54 static constexpr uint64_t kInvalidThreadID = UINT64_MAX;
anatofuz
parents:
diff changeset
55 // Get the current thread ID, or kInvalidThreadID if failure. Note: This
anatofuz
parents:
diff changeset
56 // implementation is platform-specific.
anatofuz
parents:
diff changeset
57 uint64_t getThreadID();
anatofuz
parents:
diff changeset
58
anatofuz
parents:
diff changeset
59 // This struct contains all the metadata recorded about a single allocation made
anatofuz
parents:
diff changeset
60 // by GWP-ASan. If `AllocationMetadata.Addr` is zero, the metadata is non-valid.
anatofuz
parents:
diff changeset
61 struct AllocationMetadata {
anatofuz
parents:
diff changeset
62 // The number of bytes used to store a compressed stack frame. On 64-bit
anatofuz
parents:
diff changeset
63 // platforms, assuming a compression ratio of 50%, this should allow us to
anatofuz
parents:
diff changeset
64 // store ~64 frames per trace.
anatofuz
parents:
diff changeset
65 static constexpr size_t kStackFrameStorageBytes = 256;
anatofuz
parents:
diff changeset
66
anatofuz
parents:
diff changeset
67 // Maximum number of stack frames to collect on allocation/deallocation. The
anatofuz
parents:
diff changeset
68 // actual number of collected frames may be less than this as the stack
anatofuz
parents:
diff changeset
69 // frames are compressed into a fixed memory range.
anatofuz
parents:
diff changeset
70 static constexpr size_t kMaxTraceLengthToCollect = 128;
anatofuz
parents:
diff changeset
71
anatofuz
parents:
diff changeset
72 // Records the given allocation metadata into this struct.
221
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
73 void RecordAllocation(uintptr_t Addr, size_t RequestedSize);
150
anatofuz
parents:
diff changeset
74 // Record that this allocation is now deallocated.
anatofuz
parents:
diff changeset
75 void RecordDeallocation();
anatofuz
parents:
diff changeset
76
anatofuz
parents:
diff changeset
77 struct CallSiteInfo {
anatofuz
parents:
diff changeset
78 // Record the current backtrace to this callsite.
anatofuz
parents:
diff changeset
79 void RecordBacktrace(options::Backtrace_t Backtrace);
anatofuz
parents:
diff changeset
80
anatofuz
parents:
diff changeset
81 // The compressed backtrace to the allocation/deallocation.
anatofuz
parents:
diff changeset
82 uint8_t CompressedTrace[kStackFrameStorageBytes];
anatofuz
parents:
diff changeset
83 // The thread ID for this trace, or kInvalidThreadID if not available.
anatofuz
parents:
diff changeset
84 uint64_t ThreadID = kInvalidThreadID;
anatofuz
parents:
diff changeset
85 // The size of the compressed trace (in bytes). Zero indicates that no
anatofuz
parents:
diff changeset
86 // trace was collected.
anatofuz
parents:
diff changeset
87 size_t TraceSize = 0;
anatofuz
parents:
diff changeset
88 };
anatofuz
parents:
diff changeset
89
anatofuz
parents:
diff changeset
90 // The address of this allocation. If zero, the rest of this struct isn't
anatofuz
parents:
diff changeset
91 // valid, as the allocation has never occurred.
anatofuz
parents:
diff changeset
92 uintptr_t Addr = 0;
anatofuz
parents:
diff changeset
93 // Represents the actual size of the allocation.
221
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
94 size_t RequestedSize = 0;
150
anatofuz
parents:
diff changeset
95
anatofuz
parents:
diff changeset
96 CallSiteInfo AllocationTrace;
anatofuz
parents:
diff changeset
97 CallSiteInfo DeallocationTrace;
anatofuz
parents:
diff changeset
98
anatofuz
parents:
diff changeset
99 // Whether this allocation has been deallocated yet.
anatofuz
parents:
diff changeset
100 bool IsDeallocated = false;
anatofuz
parents:
diff changeset
101 };
anatofuz
parents:
diff changeset
102
anatofuz
parents:
diff changeset
103 // This holds the state that's shared between the GWP-ASan allocator and the
anatofuz
parents:
diff changeset
104 // crash handler. This, in conjunction with the Metadata array, forms the entire
anatofuz
parents:
diff changeset
105 // set of information required for understanding a GWP-ASan crash.
anatofuz
parents:
diff changeset
106 struct AllocatorState {
221
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
107 constexpr AllocatorState() {}
236
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
108 AllocatorVersionMagic VersionMagic{};
221
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
109
150
anatofuz
parents:
diff changeset
110 // Returns whether the provided pointer is a current sampled allocation that
anatofuz
parents:
diff changeset
111 // is owned by this pool.
anatofuz
parents:
diff changeset
112 GWP_ASAN_ALWAYS_INLINE bool pointerIsMine(const void *Ptr) const {
anatofuz
parents:
diff changeset
113 uintptr_t P = reinterpret_cast<uintptr_t>(Ptr);
anatofuz
parents:
diff changeset
114 return P < GuardedPagePoolEnd && GuardedPagePool <= P;
anatofuz
parents:
diff changeset
115 }
anatofuz
parents:
diff changeset
116
anatofuz
parents:
diff changeset
117 // Returns the address of the N-th guarded slot.
anatofuz
parents:
diff changeset
118 uintptr_t slotToAddr(size_t N) const;
anatofuz
parents:
diff changeset
119
anatofuz
parents:
diff changeset
120 // Returns the largest allocation that is supported by this pool.
anatofuz
parents:
diff changeset
121 size_t maximumAllocationSize() const;
anatofuz
parents:
diff changeset
122
anatofuz
parents:
diff changeset
123 // Gets the nearest slot to the provided address.
anatofuz
parents:
diff changeset
124 size_t getNearestSlot(uintptr_t Ptr) const;
anatofuz
parents:
diff changeset
125
anatofuz
parents:
diff changeset
126 // Returns whether the provided pointer is a guard page or not. The pointer
anatofuz
parents:
diff changeset
127 // must be within memory owned by this pool, else the result is undefined.
anatofuz
parents:
diff changeset
128 bool isGuardPage(uintptr_t Ptr) const;
anatofuz
parents:
diff changeset
129
anatofuz
parents:
diff changeset
130 // The number of guarded slots that this pool holds.
anatofuz
parents:
diff changeset
131 size_t MaxSimultaneousAllocations = 0;
anatofuz
parents:
diff changeset
132
anatofuz
parents:
diff changeset
133 // Pointer to the pool of guarded slots. Note that this points to the start of
anatofuz
parents:
diff changeset
134 // the pool (which is a guard page), not a pointer to the first guarded page.
anatofuz
parents:
diff changeset
135 uintptr_t GuardedPagePool = 0;
anatofuz
parents:
diff changeset
136 uintptr_t GuardedPagePoolEnd = 0;
anatofuz
parents:
diff changeset
137
anatofuz
parents:
diff changeset
138 // Cached page size for this system in bytes.
anatofuz
parents:
diff changeset
139 size_t PageSize = 0;
anatofuz
parents:
diff changeset
140
anatofuz
parents:
diff changeset
141 // The type and address of an internally-detected failure. For INVALID_FREE
anatofuz
parents:
diff changeset
142 // and DOUBLE_FREE, these errors are detected in GWP-ASan, which will set
anatofuz
parents:
diff changeset
143 // these values and terminate the process.
anatofuz
parents:
diff changeset
144 Error FailureType = Error::UNKNOWN;
anatofuz
parents:
diff changeset
145 uintptr_t FailureAddress = 0;
anatofuz
parents:
diff changeset
146 };
anatofuz
parents:
diff changeset
147
236
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
148 // Below are various compile-time checks that the layout of the internal
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
149 // GWP-ASan structures are undisturbed. If they are disturbed, the version magic
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
150 // number needs to be increased by one, and the asserts need to be updated.
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
151 // Out-of-process crash handlers, like breakpad/crashpad, may copy the internal
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
152 // GWP-ASan structures into a minidump for offline reconstruction of the crash.
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
153 // In order to accomplish this, the offline reconstructor needs to know the
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
154 // version of GWP-ASan internal structures that it's unpacking (along with the
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
155 // architecture-specific layout info, which is left as an exercise to the crash
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
156 // handler).
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
157 static_assert(offsetof(AllocatorState, VersionMagic) == 0, "");
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
158 static_assert(sizeof(AllocatorVersionMagic) == 8, "");
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
159 #if defined(__x86_64__)
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
160 static_assert(sizeof(AllocatorState) == 56, "");
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
161 static_assert(offsetof(AllocatorState, FailureAddress) == 48, "");
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
162 static_assert(sizeof(AllocationMetadata) == 568, "");
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
163 static_assert(offsetof(AllocationMetadata, IsDeallocated) == 560, "");
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
164 #elif defined(__aarch64__)
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
165 static_assert(sizeof(AllocatorState) == 56, "");
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
166 static_assert(offsetof(AllocatorState, FailureAddress) == 48, "");
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
167 static_assert(sizeof(AllocationMetadata) == 568, "");
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
168 static_assert(offsetof(AllocationMetadata, IsDeallocated) == 560, "");
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
169 #elif defined(__i386__)
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
170 static_assert(sizeof(AllocatorState) == 32, "");
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
171 static_assert(offsetof(AllocatorState, FailureAddress) == 28, "");
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
172 static_assert(sizeof(AllocationMetadata) == 548, "");
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
173 static_assert(offsetof(AllocationMetadata, IsDeallocated) == 544, "");
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
174 #elif defined(__arm__)
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
175 static_assert(sizeof(AllocatorState) == 32, "");
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
176 static_assert(offsetof(AllocatorState, FailureAddress) == 28, "");
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
177 static_assert(sizeof(AllocationMetadata) == 560, "");
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
178 static_assert(offsetof(AllocationMetadata, IsDeallocated) == 552, "");
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
179 #endif // defined($ARCHITECTURE)
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
180
150
anatofuz
parents:
diff changeset
181 } // namespace gwp_asan
anatofuz
parents:
diff changeset
182 #endif // GWP_ASAN_COMMON_H_