1 //===-- secondary.cc --------------------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
11 #include "string_utils.h"
15 // As with the Primary, the size passed to this function includes any desired
16 // alignment, so that the frontend can align the user allocation. The hint
17 // parameter allows us to unmap spurious memory when dealing with larger
18 // (greater than a page) alignments on 32-bit platforms.
19 // Due to the sparsity of address space available on those platforms, requesting
20 // an allocation from the Secondary with a large alignment would end up wasting
21 // VA space (even though we are not committing the whole thing), hence the need
22 // to trim off some of the reserved space.
23 // For allocations requested with an alignment greater than or equal to a page,
24 // the committed memory will amount to something close to Size - AlignmentHint
25 // (pending rounding and headers).
26 void *MapAllocator::allocate(uptr Size, uptr AlignmentHint, uptr *BlockEnd) {
27 DCHECK_GT(Size, AlignmentHint);
28 const uptr PageSize = getPageSizeCached();
30 roundUpTo(Size + LargeBlock::getHeaderSize(), PageSize) + 2 * PageSize;
31 MapPlatformData Data = {};
33 reinterpret_cast<uptr>(map(nullptr, MapSize, "scudo:secondary",
34 MAP_NOACCESS | MAP_ALLOWNOMEM, &Data));
37 uptr CommitBase = MapBase + PageSize;
38 uptr MapEnd = MapBase + MapSize;
40 // In the unlikely event of alignments larger than a page, adjust the amount
41 // of memory we want to commit, and trim the extra memory.
42 if (AlignmentHint >= PageSize) {
43 // For alignments greater than or equal to a page, the user pointer (eg: the
44 // pointer that is returned by the C or C++ allocation APIs) ends up on a
45 // page boundary , and our headers will live in the preceding page.
46 CommitBase = roundUpTo(MapBase + PageSize + 1, AlignmentHint) - PageSize;
47 const uptr NewMapBase = CommitBase - PageSize;
48 DCHECK_GE(NewMapBase, MapBase);
49 // We only trim the extra memory on 32-bit platforms: 64-bit platforms
50 // are less constrained memory wise, and that saves us two syscalls.
51 if (SCUDO_WORDSIZE == 32U && NewMapBase != MapBase) {
52 unmap(reinterpret_cast<void *>(MapBase), NewMapBase - MapBase, 0, &Data);
55 const uptr NewMapEnd = CommitBase + PageSize +
56 roundUpTo((Size - AlignmentHint), PageSize) +
58 DCHECK_LE(NewMapEnd, MapEnd);
59 if (SCUDO_WORDSIZE == 32U && NewMapEnd != MapEnd) {
60 unmap(reinterpret_cast<void *>(NewMapEnd), MapEnd - NewMapEnd, 0, &Data);
65 const uptr CommitSize = MapEnd - PageSize - CommitBase;
67 reinterpret_cast<uptr>(map(reinterpret_cast<void *>(CommitBase),
68 CommitSize, "scudo:secondary", 0, &Data));
69 LargeBlock::Header *H = reinterpret_cast<LargeBlock::Header *>(Ptr);
71 H->MapSize = MapEnd - MapBase;
72 H->BlockEnd = CommitBase + CommitSize;
83 AllocatedBytes += CommitSize;
84 if (LargestSize < CommitSize)
85 LargestSize = CommitSize;
87 Stats.add(StatAllocated, CommitSize);
88 Stats.add(StatMapped, H->MapSize);
91 *BlockEnd = CommitBase + CommitSize;
92 return reinterpret_cast<void *>(Ptr + LargeBlock::getHeaderSize());
95 void MapAllocator::deallocate(void *Ptr) {
96 LargeBlock::Header *H = LargeBlock::getHeader(Ptr);
99 LargeBlock::Header *Prev = H->Prev;
100 LargeBlock::Header *Next = H->Next;
102 CHECK_EQ(Prev->Next, H);
106 CHECK_EQ(Next->Prev, H);
115 const uptr CommitSize = H->BlockEnd - reinterpret_cast<uptr>(H);
116 FreedBytes += CommitSize;
118 Stats.sub(StatAllocated, CommitSize);
119 Stats.sub(StatMapped, H->MapSize);
121 void *Addr = reinterpret_cast<void *>(H->MapBase);
122 const uptr Size = H->MapSize;
123 MapPlatformData Data;
125 unmap(Addr, Size, UNMAP_ALL, &Data);
128 void MapAllocator::printStats() const {
129 Printf("Stats: MapAllocator: allocated %zd times (%zdK), freed %zd times "
130 "(%zdK), remains %zd (%zdK) max %zdM\n",
131 NumberOfAllocs, AllocatedBytes >> 10, NumberOfFrees, FreedBytes >> 10,
132 NumberOfAllocs - NumberOfFrees, (AllocatedBytes - FreedBytes) >> 10,