1 | //===-- common.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 | #ifndef SCUDO_COMMON_H_ |
10 | #define SCUDO_COMMON_H_ |
11 | |
12 | #include "internal_defs.h" |
13 | |
14 | #include "fuchsia.h" |
15 | #include "linux.h" |
16 | #include "trusty.h" |
17 | |
18 | #include <stddef.h> |
19 | #include <string.h> |
20 | #include <unistd.h> |
21 | |
22 | namespace scudo { |
23 | |
24 | template <class Dest, class Source> inline Dest bit_cast(const Source &S) { |
25 | static_assert(sizeof(Dest) == sizeof(Source), "" ); |
26 | Dest D; |
27 | memcpy(&D, &S, sizeof(D)); |
28 | return D; |
29 | } |
30 | |
31 | inline constexpr bool isPowerOfTwo(uptr X) { |
32 | if (X == 0) |
33 | return false; |
34 | return (X & (X - 1)) == 0; |
35 | } |
36 | |
37 | inline constexpr uptr roundUp(uptr X, uptr Boundary) { |
38 | DCHECK(isPowerOfTwo(Boundary)); |
39 | return (X + Boundary - 1) & ~(Boundary - 1); |
40 | } |
41 | inline constexpr uptr roundUpSlow(uptr X, uptr Boundary) { |
42 | return ((X + Boundary - 1) / Boundary) * Boundary; |
43 | } |
44 | |
45 | inline constexpr uptr roundDown(uptr X, uptr Boundary) { |
46 | DCHECK(isPowerOfTwo(Boundary)); |
47 | return X & ~(Boundary - 1); |
48 | } |
49 | inline constexpr uptr roundDownSlow(uptr X, uptr Boundary) { |
50 | return (X / Boundary) * Boundary; |
51 | } |
52 | |
53 | inline constexpr bool isAligned(uptr X, uptr Alignment) { |
54 | DCHECK(isPowerOfTwo(Alignment)); |
55 | return (X & (Alignment - 1)) == 0; |
56 | } |
57 | inline constexpr bool isAlignedSlow(uptr X, uptr Alignment) { |
58 | return X % Alignment == 0; |
59 | } |
60 | |
61 | template <class T> constexpr T Min(T A, T B) { return A < B ? A : B; } |
62 | |
63 | template <class T> constexpr T Max(T A, T B) { return A > B ? A : B; } |
64 | |
65 | template <class T> void Swap(T &A, T &B) { |
66 | T Tmp = A; |
67 | A = B; |
68 | B = Tmp; |
69 | } |
70 | |
71 | inline uptr getMostSignificantSetBitIndex(uptr X) { |
72 | DCHECK_NE(X, 0U); |
73 | return SCUDO_WORDSIZE - 1U - static_cast<uptr>(__builtin_clzl(X)); |
74 | } |
75 | |
76 | inline uptr roundUpPowerOfTwo(uptr Size) { |
77 | DCHECK(Size); |
78 | if (isPowerOfTwo(X: Size)) |
79 | return Size; |
80 | const uptr Up = getMostSignificantSetBitIndex(X: Size); |
81 | DCHECK_LT(Size, (1UL << (Up + 1))); |
82 | DCHECK_GT(Size, (1UL << Up)); |
83 | return 1UL << (Up + 1); |
84 | } |
85 | |
86 | inline uptr getLeastSignificantSetBitIndex(uptr X) { |
87 | DCHECK_NE(X, 0U); |
88 | return static_cast<uptr>(__builtin_ctzl(X)); |
89 | } |
90 | |
91 | inline uptr getLog2(uptr X) { |
92 | DCHECK(isPowerOfTwo(X)); |
93 | return getLeastSignificantSetBitIndex(X); |
94 | } |
95 | |
96 | inline u32 getRandomU32(u32 *State) { |
97 | // ANSI C linear congruential PRNG (16-bit output). |
98 | // return (*State = *State * 1103515245 + 12345) >> 16; |
99 | // XorShift (32-bit output). |
100 | *State ^= *State << 13; |
101 | *State ^= *State >> 17; |
102 | *State ^= *State << 5; |
103 | return *State; |
104 | } |
105 | |
106 | inline u32 getRandomModN(u32 *State, u32 N) { |
107 | return getRandomU32(State) % N; // [0, N) |
108 | } |
109 | |
110 | template <typename T> inline void shuffle(T *A, u32 N, u32 *RandState) { |
111 | if (N <= 1) |
112 | return; |
113 | u32 State = *RandState; |
114 | for (u32 I = N - 1; I > 0; I--) |
115 | Swap(A[I], A[getRandomModN(State: &State, N: I + 1)]); |
116 | *RandState = State; |
117 | } |
118 | |
119 | inline void computePercentage(uptr Numerator, uptr Denominator, uptr *Integral, |
120 | uptr *Fractional) { |
121 | constexpr uptr Digits = 100; |
122 | if (Denominator == 0) { |
123 | *Integral = 100; |
124 | *Fractional = 0; |
125 | return; |
126 | } |
127 | |
128 | *Integral = Numerator * Digits / Denominator; |
129 | *Fractional = |
130 | (((Numerator * Digits) % Denominator) * Digits + Denominator / 2) / |
131 | Denominator; |
132 | } |
133 | |
134 | // Platform specific functions. |
135 | |
136 | extern uptr PageSizeCached; |
137 | uptr getPageSizeSlow(); |
138 | inline uptr getPageSizeCached() { |
139 | #if SCUDO_ANDROID && defined(PAGE_SIZE) |
140 | // Most Android builds have a build-time constant page size. |
141 | return PAGE_SIZE; |
142 | #endif |
143 | if (LIKELY(PageSizeCached)) |
144 | return PageSizeCached; |
145 | return getPageSizeSlow(); |
146 | } |
147 | |
148 | // Returns 0 if the number of CPUs could not be determined. |
149 | u32 getNumberOfCPUs(); |
150 | |
151 | const char *getEnv(const char *Name); |
152 | |
153 | u64 getMonotonicTime(); |
154 | // Gets the time faster but with less accuracy. Can call getMonotonicTime |
155 | // if no fast version is available. |
156 | u64 getMonotonicTimeFast(); |
157 | |
158 | u32 getThreadID(); |
159 | |
160 | // Our randomness gathering function is limited to 256 bytes to ensure we get |
161 | // as many bytes as requested, and avoid interruptions (on Linux). |
162 | constexpr uptr MaxRandomLength = 256U; |
163 | bool getRandom(void *Buffer, uptr Length, bool Blocking = false); |
164 | |
165 | // Platform memory mapping functions. |
166 | |
167 | #define MAP_ALLOWNOMEM (1U << 0) |
168 | #define MAP_NOACCESS (1U << 1) |
169 | #define MAP_RESIZABLE (1U << 2) |
170 | #define MAP_MEMTAG (1U << 3) |
171 | #define MAP_PRECOMMIT (1U << 4) |
172 | |
173 | // Our platform memory mapping use is restricted to 3 scenarios: |
174 | // - reserve memory at a random address (MAP_NOACCESS); |
175 | // - commit memory in a previously reserved space; |
176 | // - commit memory at a random address. |
177 | // As such, only a subset of parameters combinations is valid, which is checked |
178 | // by the function implementation. The Data parameter allows to pass opaque |
179 | // platform specific data to the function. |
180 | // Returns nullptr on error or dies if MAP_ALLOWNOMEM is not specified. |
181 | void *map(void *Addr, uptr Size, const char *Name, uptr Flags = 0, |
182 | MapPlatformData *Data = nullptr); |
183 | |
184 | // Indicates that we are getting rid of the whole mapping, which might have |
185 | // further consequences on Data, depending on the platform. |
186 | #define UNMAP_ALL (1U << 0) |
187 | |
188 | void unmap(void *Addr, uptr Size, uptr Flags = 0, |
189 | MapPlatformData *Data = nullptr); |
190 | |
191 | void setMemoryPermission(uptr Addr, uptr Size, uptr Flags, |
192 | MapPlatformData *Data = nullptr); |
193 | |
194 | void releasePagesToOS(uptr BaseAddress, uptr Offset, uptr Size, |
195 | MapPlatformData *Data = nullptr); |
196 | |
197 | // Logging related functions. |
198 | |
199 | void setAbortMessage(const char *Message); |
200 | |
201 | struct BlockInfo { |
202 | uptr BlockBegin; |
203 | uptr BlockSize; |
204 | uptr RegionBegin; |
205 | uptr RegionEnd; |
206 | }; |
207 | |
208 | enum class Option : u8 { |
209 | ReleaseInterval, // Release to OS interval in milliseconds. |
210 | MemtagTuning, // Whether to tune tagging for UAF or overflow. |
211 | ThreadDisableMemInit, // Whether to disable automatic heap initialization and, |
212 | // where possible, memory tagging, on this thread. |
213 | MaxCacheEntriesCount, // Maximum number of blocks that can be cached. |
214 | MaxCacheEntrySize, // Maximum size of a block that can be cached. |
215 | MaxTSDsCount, // Number of usable TSDs for the shared registry. |
216 | }; |
217 | |
218 | enum class ReleaseToOS : u8 { |
219 | Normal, // Follow the normal rules for releasing pages to the OS |
220 | Force, // Force release pages to the OS, but avoid cases that take too long. |
221 | ForceAll, // Force release every page possible regardless of how long it will |
222 | // take. |
223 | }; |
224 | |
225 | constexpr unsigned char PatternFillByte = 0xAB; |
226 | |
227 | enum FillContentsMode { |
228 | NoFill = 0, |
229 | ZeroFill = 1, |
230 | PatternOrZeroFill = 2 // Pattern fill unless the memory is known to be |
231 | // zero-initialized already. |
232 | }; |
233 | |
234 | } // namespace scudo |
235 | |
236 | #endif // SCUDO_COMMON_H_ |
237 | |