xref: /aosp_15_r20/external/scudo/standalone/common.h (revision 76559068c068bd27e82aff38fac3bfc865233bca)
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 
bit_cast(const Source & S)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 
isPowerOfTwo(uptr X)31 inline constexpr bool isPowerOfTwo(uptr X) {
32   if (X == 0)
33     return false;
34   return (X & (X - 1)) == 0;
35 }
36 
roundUp(uptr X,uptr Boundary)37 inline constexpr uptr roundUp(uptr X, uptr Boundary) {
38   DCHECK(isPowerOfTwo(Boundary));
39   return (X + Boundary - 1) & ~(Boundary - 1);
40 }
roundUpSlow(uptr X,uptr Boundary)41 inline constexpr uptr roundUpSlow(uptr X, uptr Boundary) {
42   return ((X + Boundary - 1) / Boundary) * Boundary;
43 }
44 
roundDown(uptr X,uptr Boundary)45 inline constexpr uptr roundDown(uptr X, uptr Boundary) {
46   DCHECK(isPowerOfTwo(Boundary));
47   return X & ~(Boundary - 1);
48 }
roundDownSlow(uptr X,uptr Boundary)49 inline constexpr uptr roundDownSlow(uptr X, uptr Boundary) {
50   return (X / Boundary) * Boundary;
51 }
52 
isAligned(uptr X,uptr Alignment)53 inline constexpr bool isAligned(uptr X, uptr Alignment) {
54   DCHECK(isPowerOfTwo(Alignment));
55   return (X & (Alignment - 1)) == 0;
56 }
isAlignedSlow(uptr X,uptr Alignment)57 inline constexpr bool isAlignedSlow(uptr X, uptr Alignment) {
58   return X % Alignment == 0;
59 }
60 
Min(T A,T B)61 template <class T> constexpr T Min(T A, T B) { return A < B ? A : B; }
62 
Max(T A,T B)63 template <class T> constexpr T Max(T A, T B) { return A > B ? A : B; }
64 
Swap(T & A,T & B)65 template <class T> void Swap(T &A, T &B) {
66   T Tmp = A;
67   A = B;
68   B = Tmp;
69 }
70 
getMostSignificantSetBitIndex(uptr X)71 inline uptr getMostSignificantSetBitIndex(uptr X) {
72   DCHECK_NE(X, 0U);
73   return SCUDO_WORDSIZE - 1U - static_cast<uptr>(__builtin_clzl(X));
74 }
75 
roundUpPowerOfTwo(uptr Size)76 inline uptr roundUpPowerOfTwo(uptr Size) {
77   DCHECK(Size);
78   if (isPowerOfTwo(Size))
79     return Size;
80   const uptr Up = getMostSignificantSetBitIndex(Size);
81   DCHECK_LT(Size, (1UL << (Up + 1)));
82   DCHECK_GT(Size, (1UL << Up));
83   return 1UL << (Up + 1);
84 }
85 
getLeastSignificantSetBitIndex(uptr X)86 inline uptr getLeastSignificantSetBitIndex(uptr X) {
87   DCHECK_NE(X, 0U);
88   return static_cast<uptr>(__builtin_ctzl(X));
89 }
90 
getLog2(uptr X)91 inline uptr getLog2(uptr X) {
92   DCHECK(isPowerOfTwo(X));
93   return getLeastSignificantSetBitIndex(X);
94 }
95 
getRandomU32(u32 * State)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 
getRandomModN(u32 * State,u32 N)106 inline u32 getRandomModN(u32 *State, u32 N) {
107   return getRandomU32(State) % N; // [0, N)
108 }
109 
shuffle(T * A,u32 N,u32 * RandState)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, I + 1)]);
116   *RandState = State;
117 }
118 
computePercentage(uptr Numerator,uptr Denominator,uptr * Integral,uptr * Fractional)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 #if defined(SCUDO_PAGE_SIZE)
137 
getPageSizeCached()138 inline constexpr uptr getPageSizeCached() { return SCUDO_PAGE_SIZE; }
139 
getPageSizeSlow()140 inline constexpr uptr getPageSizeSlow() { return getPageSizeCached(); }
141 
getPageSizeLogCached()142 inline constexpr uptr getPageSizeLogCached() {
143   return static_cast<uptr>(__builtin_ctzl(SCUDO_PAGE_SIZE));
144 }
145 
146 #else
147 
148 extern uptr PageSizeCached;
149 extern uptr PageSizeLogCached;
150 
151 uptr getPageSizeSlow();
152 
getPageSizeCached()153 inline uptr getPageSizeCached() {
154   if (LIKELY(PageSizeCached))
155     return PageSizeCached;
156   return getPageSizeSlow();
157 }
158 
getPageSizeLogCached()159 inline uptr getPageSizeLogCached() {
160   if (LIKELY(PageSizeLogCached))
161     return PageSizeLogCached;
162   // PageSizeLogCached and PageSizeCached are both set in getPageSizeSlow()
163   getPageSizeSlow();
164   DCHECK_NE(PageSizeLogCached, 0);
165   return PageSizeLogCached;
166 }
167 
168 #endif
169 
170 // Returns 0 if the number of CPUs could not be determined.
171 u32 getNumberOfCPUs();
172 
173 const char *getEnv(const char *Name);
174 
175 u64 getMonotonicTime();
176 // Gets the time faster but with less accuracy. Can call getMonotonicTime
177 // if no fast version is available.
178 u64 getMonotonicTimeFast();
179 
180 u32 getThreadID();
181 
182 // Our randomness gathering function is limited to 256 bytes to ensure we get
183 // as many bytes as requested, and avoid interruptions (on Linux).
184 constexpr uptr MaxRandomLength = 256U;
185 bool getRandom(void *Buffer, uptr Length, bool Blocking = false);
186 
187 // Platform memory mapping functions.
188 
189 #define MAP_ALLOWNOMEM (1U << 0)
190 #define MAP_NOACCESS (1U << 1)
191 #define MAP_RESIZABLE (1U << 2)
192 #define MAP_MEMTAG (1U << 3)
193 #define MAP_PRECOMMIT (1U << 4)
194 
195 // Our platform memory mapping use is restricted to 3 scenarios:
196 // - reserve memory at a random address (MAP_NOACCESS);
197 // - commit memory in a previously reserved space;
198 // - commit memory at a random address.
199 // As such, only a subset of parameters combinations is valid, which is checked
200 // by the function implementation. The Data parameter allows to pass opaque
201 // platform specific data to the function.
202 // Returns nullptr on error or dies if MAP_ALLOWNOMEM is not specified.
203 void *map(void *Addr, uptr Size, const char *Name, uptr Flags = 0,
204           MapPlatformData *Data = nullptr);
205 
206 // Indicates that we are getting rid of the whole mapping, which might have
207 // further consequences on Data, depending on the platform.
208 #define UNMAP_ALL (1U << 0)
209 
210 void unmap(void *Addr, uptr Size, uptr Flags = 0,
211            MapPlatformData *Data = nullptr);
212 
213 void setMemoryPermission(uptr Addr, uptr Size, uptr Flags,
214                          MapPlatformData *Data = nullptr);
215 
216 void releasePagesToOS(uptr BaseAddress, uptr Offset, uptr Size,
217                       MapPlatformData *Data = nullptr);
218 
219 // Logging related functions.
220 
221 void setAbortMessage(const char *Message);
222 
223 struct BlockInfo {
224   uptr BlockBegin;
225   uptr BlockSize;
226   uptr RegionBegin;
227   uptr RegionEnd;
228 };
229 
230 enum class Option : u8 {
231   ReleaseInterval,      // Release to OS interval in milliseconds.
232   MemtagTuning,         // Whether to tune tagging for UAF or overflow.
233   ThreadDisableMemInit, // Whether to disable automatic heap initialization and,
234                         // where possible, memory tagging, on this thread.
235   MaxCacheEntriesCount, // Maximum number of blocks that can be cached.
236   MaxCacheEntrySize,    // Maximum size of a block that can be cached.
237   MaxTSDsCount,         // Number of usable TSDs for the shared registry.
238 };
239 
240 enum class ReleaseToOS : u8 {
241   Normal, // Follow the normal rules for releasing pages to the OS
242   Force,  // Force release pages to the OS, but avoid cases that take too long.
243   ForceAll, // Force release every page possible regardless of how long it will
244             // take.
245 };
246 
247 constexpr unsigned char PatternFillByte = 0xAB;
248 
249 enum FillContentsMode {
250   NoFill = 0,
251   ZeroFill = 1,
252   PatternOrZeroFill = 2 // Pattern fill unless the memory is known to be
253                         // zero-initialized already.
254 };
255 
256 } // namespace scudo
257 
258 #endif // SCUDO_COMMON_H_
259