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 21 namespace scudo { 22 23 template <class Dest, class Source> inline Dest bit_cast(const Source &S) { 24 static_assert(sizeof(Dest) == sizeof(Source), ""); 25 Dest D; 26 memcpy(&D, &S, sizeof(D)); 27 return D; 28 } 29 30 inline constexpr uptr roundUpTo(uptr X, uptr Boundary) { 31 return (X + Boundary - 1) & ~(Boundary - 1); 32 } 33 34 inline constexpr uptr roundDownTo(uptr X, uptr Boundary) { 35 return X & ~(Boundary - 1); 36 } 37 38 inline constexpr bool isAligned(uptr X, uptr Alignment) { 39 return (X & (Alignment - 1)) == 0; 40 } 41 42 template <class T> constexpr T Min(T A, T B) { return A < B ? A : B; } 43 44 template <class T> constexpr T Max(T A, T B) { return A > B ? A : B; } 45 46 template <class T> void Swap(T &A, T &B) { 47 T Tmp = A; 48 A = B; 49 B = Tmp; 50 } 51 52 inline bool isPowerOfTwo(uptr X) { return (X & (X - 1)) == 0; } 53 54 inline uptr getMostSignificantSetBitIndex(uptr X) { 55 DCHECK_NE(X, 0U); 56 return SCUDO_WORDSIZE - 1U - static_cast<uptr>(__builtin_clzl(X)); 57 } 58 59 inline uptr roundUpToPowerOfTwo(uptr Size) { 60 DCHECK(Size); 61 if (isPowerOfTwo(Size)) 62 return Size; 63 const uptr Up = getMostSignificantSetBitIndex(Size); 64 DCHECK_LT(Size, (1UL << (Up + 1))); 65 DCHECK_GT(Size, (1UL << Up)); 66 return 1UL << (Up + 1); 67 } 68 69 inline uptr getLeastSignificantSetBitIndex(uptr X) { 70 DCHECK_NE(X, 0U); 71 return static_cast<uptr>(__builtin_ctzl(X)); 72 } 73 74 inline uptr getLog2(uptr X) { 75 DCHECK(isPowerOfTwo(X)); 76 return getLeastSignificantSetBitIndex(X); 77 } 78 79 inline u32 getRandomU32(u32 *State) { 80 // ANSI C linear congruential PRNG (16-bit output). 81 // return (*State = *State * 1103515245 + 12345) >> 16; 82 // XorShift (32-bit output). 83 *State ^= *State << 13; 84 *State ^= *State >> 17; 85 *State ^= *State << 5; 86 return *State; 87 } 88 89 inline u32 getRandomModN(u32 *State, u32 N) { 90 return getRandomU32(State) % N; // [0, N) 91 } 92 93 template <typename T> inline void shuffle(T *A, u32 N, u32 *RandState) { 94 if (N <= 1) 95 return; 96 u32 State = *RandState; 97 for (u32 I = N - 1; I > 0; I--) 98 Swap(A[I], A[getRandomModN(&State, I + 1)]); 99 *RandState = State; 100 } 101 102 // Hardware specific inlinable functions. 103 104 inline void yieldProcessor(u8 Count) { 105 #if defined(__i386__) || defined(__x86_64__) 106 __asm__ __volatile__("" ::: "memory"); 107 for (u8 I = 0; I < Count; I++) 108 __asm__ __volatile__("pause"); 109 #elif defined(__aarch64__) || defined(__arm__) 110 __asm__ __volatile__("" ::: "memory"); 111 for (u8 I = 0; I < Count; I++) 112 __asm__ __volatile__("yield"); 113 #endif 114 __asm__ __volatile__("" ::: "memory"); 115 } 116 117 // Platform specific functions. 118 119 extern uptr PageSizeCached; 120 uptr getPageSizeSlow(); 121 inline uptr getPageSizeCached() { 122 // Bionic uses a hardcoded value. 123 if (SCUDO_ANDROID) 124 return 4096U; 125 if (LIKELY(PageSizeCached)) 126 return PageSizeCached; 127 return getPageSizeSlow(); 128 } 129 130 // Returns 0 if the number of CPUs could not be determined. 131 u32 getNumberOfCPUs(); 132 133 const char *getEnv(const char *Name); 134 135 u64 getMonotonicTime(); 136 137 u32 getThreadID(); 138 139 // Our randomness gathering function is limited to 256 bytes to ensure we get 140 // as many bytes as requested, and avoid interruptions (on Linux). 141 constexpr uptr MaxRandomLength = 256U; 142 bool getRandom(void *Buffer, uptr Length, bool Blocking = false); 143 144 // Platform memory mapping functions. 145 146 #define MAP_ALLOWNOMEM (1U << 0) 147 #define MAP_NOACCESS (1U << 1) 148 #define MAP_RESIZABLE (1U << 2) 149 #define MAP_MEMTAG (1U << 3) 150 151 // Our platform memory mapping use is restricted to 3 scenarios: 152 // - reserve memory at a random address (MAP_NOACCESS); 153 // - commit memory in a previously reserved space; 154 // - commit memory at a random address. 155 // As such, only a subset of parameters combinations is valid, which is checked 156 // by the function implementation. The Data parameter allows to pass opaque 157 // platform specific data to the function. 158 // Returns nullptr on error or dies if MAP_ALLOWNOMEM is not specified. 159 void *map(void *Addr, uptr Size, const char *Name, uptr Flags = 0, 160 MapPlatformData *Data = nullptr); 161 162 // Indicates that we are getting rid of the whole mapping, which might have 163 // further consequences on Data, depending on the platform. 164 #define UNMAP_ALL (1U << 0) 165 166 void unmap(void *Addr, uptr Size, uptr Flags = 0, 167 MapPlatformData *Data = nullptr); 168 169 void setMemoryPermission(uptr Addr, uptr Size, uptr Flags, 170 MapPlatformData *Data = nullptr); 171 172 void releasePagesToOS(uptr BaseAddress, uptr Offset, uptr Size, 173 MapPlatformData *Data = nullptr); 174 175 // Internal map & unmap fatal error. This must not call map(). SizeIfOOM shall 176 // hold the requested size on an out-of-memory error, 0 otherwise. 177 void NORETURN dieOnMapUnmapError(uptr SizeIfOOM = 0); 178 179 // Logging related functions. 180 181 void setAbortMessage(const char *Message); 182 183 struct BlockInfo { 184 uptr BlockBegin; 185 uptr BlockSize; 186 uptr RegionBegin; 187 uptr RegionEnd; 188 }; 189 190 enum class Option : u8 { 191 ReleaseInterval, // Release to OS interval in milliseconds. 192 MemtagTuning, // Whether to tune tagging for UAF or overflow. 193 ThreadDisableMemInit, // Whether to disable automatic heap initialization and, 194 // where possible, memory tagging, on this thread. 195 MaxCacheEntriesCount, // Maximum number of blocks that can be cached. 196 MaxCacheEntrySize, // Maximum size of a block that can be cached. 197 MaxTSDsCount, // Number of usable TSDs for the shared registry. 198 }; 199 200 constexpr unsigned char PatternFillByte = 0xAB; 201 202 enum FillContentsMode { 203 NoFill = 0, 204 ZeroFill = 1, 205 PatternOrZeroFill = 2 // Pattern fill unless the memory is known to be 206 // zero-initialized already. 207 }; 208 209 } // namespace scudo 210 211 #endif // SCUDO_COMMON_H_ 212