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