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(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 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, 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