xref: /freebsd/contrib/llvm-project/compiler-rt/lib/scudo/standalone/secondary.h (revision 4b50c451720d8b427757a6da1dd2bb4c52cd9e35)
1 //===-- secondary.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_SECONDARY_H_
10 #define SCUDO_SECONDARY_H_
11 
12 #include "common.h"
13 #include "mutex.h"
14 #include "stats.h"
15 
16 namespace scudo {
17 
18 // This allocator wraps the platform allocation primitives, and as such is on
19 // the slower side and should preferably be used for larger sized allocations.
20 // Blocks allocated will be preceded and followed by a guard page, and hold
21 // their own header that is not checksummed: the guard pages and the Combined
22 // header should be enough for our purpose.
23 
24 namespace LargeBlock {
25 
26 struct Header {
27   LargeBlock::Header *Prev;
28   LargeBlock::Header *Next;
29   uptr BlockEnd;
30   uptr MapBase;
31   uptr MapSize;
32   MapPlatformData Data;
33 };
34 
35 constexpr uptr getHeaderSize() {
36   return roundUpTo(sizeof(Header), 1U << SCUDO_MIN_ALIGNMENT_LOG);
37 }
38 
39 static Header *getHeader(uptr Ptr) {
40   return reinterpret_cast<Header *>(Ptr - getHeaderSize());
41 }
42 
43 static Header *getHeader(const void *Ptr) {
44   return getHeader(reinterpret_cast<uptr>(Ptr));
45 }
46 
47 } // namespace LargeBlock
48 
49 class MapAllocator {
50 public:
51   void initLinkerInitialized(GlobalStats *S) {
52     Stats.initLinkerInitialized();
53     if (S)
54       S->link(&Stats);
55   }
56   void init(GlobalStats *S) {
57     memset(this, 0, sizeof(*this));
58     initLinkerInitialized(S);
59   }
60 
61   void *allocate(uptr Size, uptr AlignmentHint = 0, uptr *BlockEnd = nullptr);
62 
63   void deallocate(void *Ptr);
64 
65   static uptr getBlockEnd(void *Ptr) {
66     return LargeBlock::getHeader(Ptr)->BlockEnd;
67   }
68 
69   static uptr getBlockSize(void *Ptr) {
70     return getBlockEnd(Ptr) - reinterpret_cast<uptr>(Ptr);
71   }
72 
73   void printStats() const;
74 
75   void disable() { Mutex.lock(); }
76 
77   void enable() { Mutex.unlock(); }
78 
79   template <typename F> void iterateOverBlocks(F Callback) const {
80     for (LargeBlock::Header *H = Tail; H != nullptr; H = H->Prev)
81       Callback(reinterpret_cast<uptr>(H) + LargeBlock::getHeaderSize());
82   }
83 
84 private:
85   HybridMutex Mutex;
86   LargeBlock::Header *Tail;
87   uptr AllocatedBytes;
88   uptr FreedBytes;
89   uptr LargestSize;
90   u32 NumberOfAllocs;
91   u32 NumberOfFrees;
92   LocalStats Stats;
93 };
94 
95 } // namespace scudo
96 
97 #endif // SCUDO_SECONDARY_H_
98