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
22namespace scudo {
23
24template <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
31inline constexpr bool isPowerOfTwo(uptr X) {
32 if (X == 0)
33 return false;
34 return (X & (X - 1)) == 0;
35}
36
37inline constexpr uptr roundUp(uptr X, uptr Boundary) {
38 DCHECK(isPowerOfTwo(Boundary));
39 return (X + Boundary - 1) & ~(Boundary - 1);
40}
41inline constexpr uptr roundUpSlow(uptr X, uptr Boundary) {
42 return ((X + Boundary - 1) / Boundary) * Boundary;
43}
44
45inline constexpr uptr roundDown(uptr X, uptr Boundary) {
46 DCHECK(isPowerOfTwo(Boundary));
47 return X & ~(Boundary - 1);
48}
49inline constexpr uptr roundDownSlow(uptr X, uptr Boundary) {
50 return (X / Boundary) * Boundary;
51}
52
53inline constexpr bool isAligned(uptr X, uptr Alignment) {
54 DCHECK(isPowerOfTwo(Alignment));
55 return (X & (Alignment - 1)) == 0;
56}
57inline constexpr bool isAlignedSlow(uptr X, uptr Alignment) {
58 return X % Alignment == 0;
59}
60
61template <class T> constexpr T Min(T A, T B) { return A < B ? A : B; }
62
63template <class T> constexpr T Max(T A, T B) { return A > B ? A : B; }
64
65template <class T> void Swap(T &A, T &B) {
66 T Tmp = A;
67 A = B;
68 B = Tmp;
69}
70
71inline uptr getMostSignificantSetBitIndex(uptr X) {
72 DCHECK_NE(X, 0U);
73 return SCUDO_WORDSIZE - 1U - static_cast<uptr>(__builtin_clzl(X));
74}
75
76inline 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
86inline uptr getLeastSignificantSetBitIndex(uptr X) {
87 DCHECK_NE(X, 0U);
88 return static_cast<uptr>(__builtin_ctzl(X));
89}
90
91inline uptr getLog2(uptr X) {
92 DCHECK(isPowerOfTwo(X));
93 return getLeastSignificantSetBitIndex(X);
94}
95
96inline 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
106inline u32 getRandomModN(u32 *State, u32 N) {
107 return getRandomU32(State) % N; // [0, N)
108}
109
110template <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
119inline 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
136extern uptr PageSizeCached;
137uptr getPageSizeSlow();
138inline 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.
149u32 getNumberOfCPUs();
150
151const char *getEnv(const char *Name);
152
153u64 getMonotonicTime();
154// Gets the time faster but with less accuracy. Can call getMonotonicTime
155// if no fast version is available.
156u64 getMonotonicTimeFast();
157
158u32 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).
162constexpr uptr MaxRandomLength = 256U;
163bool 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.
181void *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
188void unmap(void *Addr, uptr Size, uptr Flags = 0,
189 MapPlatformData *Data = nullptr);
190
191void setMemoryPermission(uptr Addr, uptr Size, uptr Flags,
192 MapPlatformData *Data = nullptr);
193
194void releasePagesToOS(uptr BaseAddress, uptr Offset, uptr Size,
195 MapPlatformData *Data = nullptr);
196
197// Logging related functions.
198
199void setAbortMessage(const char *Message);
200
201struct BlockInfo {
202 uptr BlockBegin;
203 uptr BlockSize;
204 uptr RegionBegin;
205 uptr RegionEnd;
206};
207
208enum 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
218enum 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
225constexpr unsigned char PatternFillByte = 0xAB;
226
227enum 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