xref: /freebsd/contrib/llvm-project/compiler-rt/lib/scudo/standalone/common.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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  extern uptr PageSizeCached;
137  uptr getPageSizeSlow();
getPageSizeCached()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