Skip to content

Commit 0923963

Browse files
committed
[scudo] Manage pages with MemMap in Secondary Allocator
Replace the uses of raw map()/unmap(), .etc calls with MemMap. Also remove the direct use of MapPlatformData in the secondary allocator. Also add setMemoryPermission() in MemMap. Reviewed By: cryptoad Differential Revision: https://reviews.llvm.org/D146454
1 parent 405ceaa commit 0923963

File tree

4 files changed

+67
-60
lines changed

4 files changed

+67
-60
lines changed

compiler-rt/lib/scudo/standalone/mem_map.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@ void MemMapDefault::releaseAndZeroPagesToOSImpl(uptr From, uptr Size) {
4646
return ::scudo::releasePagesToOS(Base, From - Base, Size, &Data);
4747
}
4848

49+
void MemMapDefault::setMemoryPermissionImpl(uptr Addr, uptr Size, uptr Flags) {
50+
return ::scudo::setMemoryPermission(Addr, Size, Flags);
51+
}
52+
4953
void ReservedMemoryDefault::releaseImpl() {
5054
::scudo::unmap(reinterpret_cast<void *>(Base), Capacity, UNMAP_ALL, &Data);
5155
}

compiler-rt/lib/scudo/standalone/mem_map.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ class MemMapDefault final : public MemMapBase<MemMapDefault> {
3434
bool mapImpl(uptr Addr, uptr Size, const char *Name, uptr Flags);
3535
void unmapImpl(uptr Addr, uptr Size);
3636
bool remapImpl(uptr Addr, uptr Size, const char *Name, uptr Flags);
37+
void setMemoryPermissionImpl(uptr Addr, uptr Size, uptr Flags);
3738
void releasePagesToOSImpl(uptr From, uptr Size) {
3839
return releaseAndZeroPagesToOSImpl(From, Size);
3940
}

compiler-rt/lib/scudo/standalone/mem_map_base.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,15 @@ template <class Derived> class MemMapBase {
4545
return invokeImpl(&Derived::remapImpl, Addr, Size, Name, Flags);
4646
}
4747

48+
// This is used to update the pages' access permission. For example, mark
49+
// pages as no read/write permission.
50+
void setMemoryPermission(uptr Addr, uptr Size, uptr Flags) {
51+
DCHECK(isAllocated());
52+
DCHECK((Addr >= getBase()) || (Addr + Size <= getBase() + getCapacity()));
53+
return static_cast<Derived *>(this)->setMemoryPermissionImpl(Addr, Size,
54+
Flags);
55+
}
56+
4857
// Suggest releasing a set of contiguous physical pages back to the OS. Note
4958
// that only physical pages are supposed to be released. Any release of
5059
// virtual pages may lead to undefined behavior.

compiler-rt/lib/scudo/standalone/secondary.h

Lines changed: 53 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "chunk.h"
1313
#include "common.h"
1414
#include "list.h"
15+
#include "mem_map.h"
1516
#include "memtag.h"
1617
#include "mutex.h"
1718
#include "options.h"
@@ -37,9 +38,7 @@ struct alignas(Max<uptr>(archSupportsMemoryTagging()
3738
LargeBlock::Header *Next;
3839
uptr CommitBase;
3940
uptr CommitSize;
40-
uptr MapBase;
41-
uptr MapSize;
42-
[[no_unique_address]] MapPlatformData Data;
41+
MemMapT MemMap;
4342
};
4443

4544
static_assert(sizeof(Header) % (1U << SCUDO_MIN_ALIGNMENT_LOG) == 0, "");
@@ -66,8 +65,11 @@ template <typename Config> static Header *getHeader(const void *Ptr) {
6665
} // namespace LargeBlock
6766

6867
static void unmap(LargeBlock::Header *H) {
69-
MapPlatformData Data = H->Data;
70-
unmap(reinterpret_cast<void *>(H->MapBase), H->MapSize, UNMAP_ALL, &Data);
68+
// Note that the `H->MapMap` is stored on the pages managed by itself. Take
69+
// over the ownership before unmap() so that any operation along with unmap()
70+
// won't touch inaccessible pages.
71+
MemMapT MemMap = H->MemMap;
72+
MemMap.unmap(MemMap.getBase(), MemMap.getCapacity());
7173
}
7274

7375
class MapAllocatorNoCache {
@@ -97,20 +99,19 @@ static const uptr MaxUnusedCachePages = 4U;
9799

98100
template <typename Config>
99101
void mapSecondary(Options Options, uptr CommitBase, uptr CommitSize,
100-
uptr AllocPos, uptr Flags, MapPlatformData *Data) {
102+
uptr AllocPos, uptr Flags, MemMapT &MemMap) {
101103
const uptr MaxUnusedCacheBytes = MaxUnusedCachePages * getPageSizeCached();
102104
if (useMemoryTagging<Config>(Options) && CommitSize > MaxUnusedCacheBytes) {
103105
const uptr UntaggedPos = Max(AllocPos, CommitBase + MaxUnusedCacheBytes);
104-
map(reinterpret_cast<void *>(CommitBase), UntaggedPos - CommitBase,
105-
"scudo:secondary", MAP_RESIZABLE | MAP_MEMTAG | Flags, Data);
106-
map(reinterpret_cast<void *>(UntaggedPos),
107-
CommitBase + CommitSize - UntaggedPos, "scudo:secondary",
108-
MAP_RESIZABLE | Flags, Data);
106+
MemMap.remap(CommitBase, UntaggedPos - CommitBase, "scudo:secondary",
107+
MAP_RESIZABLE | MAP_MEMTAG | Flags);
108+
MemMap.remap(UntaggedPos, CommitBase + CommitSize - UntaggedPos,
109+
"scudo:secondary", MAP_RESIZABLE | Flags);
109110
} else {
110-
map(reinterpret_cast<void *>(CommitBase), CommitSize, "scudo:secondary",
111+
const uptr RemapFlags =
111112
MAP_RESIZABLE | (useMemoryTagging<Config>(Options) ? MAP_MEMTAG : 0) |
112-
Flags,
113-
Data);
113+
Flags;
114+
MemMap.remap(CommitBase, CommitSize, "scudo:secondary", RemapFlags);
114115
}
115116
}
116117

@@ -155,10 +156,8 @@ template <typename Config> class MapAllocatorCache {
155156
CachedBlock Entry;
156157
Entry.CommitBase = H->CommitBase;
157158
Entry.CommitSize = H->CommitSize;
158-
Entry.MapBase = H->MapBase;
159-
Entry.MapSize = H->MapSize;
160159
Entry.BlockBegin = reinterpret_cast<uptr>(H + 1);
161-
Entry.Data = H->Data;
160+
Entry.MemMap = H->MemMap;
162161
Entry.Time = Time;
163162
if (useMemoryTagging<Config>(Options)) {
164163
if (Interval == 0 && !SCUDO_FUCHSIA) {
@@ -168,13 +167,13 @@ template <typename Config> class MapAllocatorCache {
168167
// on top so we just do the two syscalls there.
169168
Entry.Time = 0;
170169
mapSecondary<Config>(Options, Entry.CommitBase, Entry.CommitSize,
171-
Entry.CommitBase, MAP_NOACCESS, &Entry.Data);
170+
Entry.CommitBase, MAP_NOACCESS, Entry.MemMap);
172171
} else {
173-
setMemoryPermission(Entry.CommitBase, Entry.CommitSize, MAP_NOACCESS,
174-
&Entry.Data);
172+
Entry.MemMap.setMemoryPermission(Entry.CommitBase, Entry.CommitSize,
173+
MAP_NOACCESS);
175174
}
176175
} else if (Interval == 0) {
177-
releasePagesToOS(Entry.CommitBase, 0, Entry.CommitSize, &Entry.Data);
176+
Entry.MemMap.releasePagesToOS(Entry.CommitBase, Entry.CommitSize);
178177
Entry.Time = 0;
179178
}
180179
do {
@@ -223,8 +222,7 @@ template <typename Config> class MapAllocatorCache {
223222
else if (Interval >= 0)
224223
releaseOlderThan(Time - static_cast<u64>(Interval) * 1000000);
225224
if (!EntryCached)
226-
unmap(reinterpret_cast<void *>(Entry.MapBase), Entry.MapSize, UNMAP_ALL,
227-
&Entry.Data);
225+
Entry.MemMap.unmap(Entry.MemMap.getBase(), Entry.MemMap.getCapacity());
228226
}
229227

230228
bool retrieve(Options Options, uptr Size, uptr Alignment,
@@ -267,7 +265,7 @@ template <typename Config> class MapAllocatorCache {
267265
LargeBlock::addHeaderTag<Config>(HeaderPos));
268266
*Zeroed = Entry.Time == 0;
269267
if (useMemoryTagging<Config>(Options))
270-
setMemoryPermission(Entry.CommitBase, Entry.CommitSize, 0, &Entry.Data);
268+
Entry.MemMap.setMemoryPermission(Entry.CommitBase, Entry.CommitSize, 0);
271269
uptr NewBlockBegin = reinterpret_cast<uptr>(*H + 1);
272270
if (useMemoryTagging<Config>(Options)) {
273271
if (*Zeroed) {
@@ -282,9 +280,7 @@ template <typename Config> class MapAllocatorCache {
282280
}
283281
(*H)->CommitBase = Entry.CommitBase;
284282
(*H)->CommitSize = Entry.CommitSize;
285-
(*H)->MapBase = Entry.MapBase;
286-
(*H)->MapSize = Entry.MapSize;
287-
(*H)->Data = Entry.Data;
283+
(*H)->MemMap = Entry.MemMap;
288284
return true;
289285
}
290286

@@ -323,16 +319,18 @@ template <typename Config> class MapAllocatorCache {
323319
ScopedLock L(Mutex);
324320
for (u32 I = 0; I != Config::SecondaryCacheQuarantineSize; ++I) {
325321
if (Quarantine[I].CommitBase) {
326-
unmap(reinterpret_cast<void *>(Quarantine[I].MapBase),
327-
Quarantine[I].MapSize, UNMAP_ALL, &Quarantine[I].Data);
322+
MemMapT &MemMap = Quarantine[I].MemMap;
323+
MemMap.unmap(MemMap.getBase(), MemMap.getCapacity());
328324
Quarantine[I].CommitBase = 0;
329325
}
330326
}
331327
const u32 MaxCount = atomic_load_relaxed(&MaxEntriesCount);
332-
for (u32 I = 0; I < MaxCount; I++)
333-
if (Entries[I].CommitBase)
334-
setMemoryPermission(Entries[I].CommitBase, Entries[I].CommitSize, 0,
335-
&Entries[I].Data);
328+
for (u32 I = 0; I < MaxCount; I++) {
329+
if (Entries[I].CommitBase) {
330+
Entries[I].MemMap.setMemoryPermission(Entries[I].CommitBase,
331+
Entries[I].CommitSize, 0);
332+
}
333+
}
336334
QuarantinePos = -1U;
337335
}
338336

@@ -344,38 +342,31 @@ template <typename Config> class MapAllocatorCache {
344342

345343
private:
346344
void empty() {
347-
struct {
348-
void *MapBase;
349-
uptr MapSize;
350-
MapPlatformData Data;
351-
} MapInfo[Config::SecondaryCacheEntriesArraySize];
345+
MemMapT MapInfo[Config::SecondaryCacheEntriesArraySize];
352346
uptr N = 0;
353347
{
354348
ScopedLock L(Mutex);
355349
for (uptr I = 0; I < Config::SecondaryCacheEntriesArraySize; I++) {
356350
if (!Entries[I].CommitBase)
357351
continue;
358-
MapInfo[N].MapBase = reinterpret_cast<void *>(Entries[I].MapBase);
359-
MapInfo[N].MapSize = Entries[I].MapSize;
360-
MapInfo[N].Data = Entries[I].Data;
352+
MapInfo[N] = Entries[I].MemMap;
361353
Entries[I].CommitBase = 0;
362354
N++;
363355
}
364356
EntriesCount = 0;
365357
IsFullEvents = 0;
366358
}
367-
for (uptr I = 0; I < N; I++)
368-
unmap(MapInfo[I].MapBase, MapInfo[I].MapSize, UNMAP_ALL,
369-
&MapInfo[I].Data);
359+
for (uptr I = 0; I < N; I++) {
360+
MemMapT &MemMap = MapInfo[I];
361+
MemMap.unmap(MemMap.getBase(), MemMap.getCapacity());
362+
}
370363
}
371364

372365
struct CachedBlock {
373366
uptr CommitBase;
374367
uptr CommitSize;
375-
uptr MapBase;
376-
uptr MapSize;
377368
uptr BlockBegin;
378-
[[no_unique_address]] MapPlatformData Data;
369+
MemMapT MemMap;
379370
u64 Time;
380371
};
381372

@@ -387,7 +378,7 @@ template <typename Config> class MapAllocatorCache {
387378
OldestTime = Entry.Time;
388379
return;
389380
}
390-
releasePagesToOS(Entry.CommitBase, 0, Entry.CommitSize, &Entry.Data);
381+
Entry.MemMap.releasePagesToOS(Entry.CommitBase, Entry.CommitSize);
391382
Entry.Time = 0;
392383
}
393384

@@ -538,16 +529,20 @@ void *MapAllocator<Config>::allocate(Options Options, uptr Size, uptr Alignment,
538529
AllocatedBytes += BlockSize;
539530
NumberOfAllocs++;
540531
Stats.add(StatAllocated, BlockSize);
541-
Stats.add(StatMapped, H->MapSize);
532+
Stats.add(StatMapped, H->MemMap.getCapacity());
542533
}
543534
return Ptr;
544535
}
545536
}
546537

547-
MapPlatformData Data = {};
538+
ReservedMemoryT ReservedMemory;
548539
const uptr MapSize = RoundedSize + 2 * PageSize;
549-
uptr MapBase = reinterpret_cast<uptr>(
550-
map(nullptr, MapSize, nullptr, MAP_NOACCESS | MAP_ALLOWNOMEM, &Data));
540+
ReservedMemory.create(/*Addr=*/0U, MapSize, nullptr, MAP_ALLOWNOMEM);
541+
542+
// Take the entire ownership of reserved region.
543+
MemMapT MemMap = ReservedMemory.dispatch(ReservedMemory.getBase(),
544+
ReservedMemory.getCapacity());
545+
uptr MapBase = MemMap.getBase();
551546
if (UNLIKELY(!MapBase))
552547
return nullptr;
553548
uptr CommitBase = MapBase + PageSize;
@@ -565,33 +560,31 @@ void *MapAllocator<Config>::allocate(Options Options, uptr Size, uptr Alignment,
565560
// We only trim the extra memory on 32-bit platforms: 64-bit platforms
566561
// are less constrained memory wise, and that saves us two syscalls.
567562
if (SCUDO_WORDSIZE == 32U && NewMapBase != MapBase) {
568-
unmap(reinterpret_cast<void *>(MapBase), NewMapBase - MapBase, 0, &Data);
563+
MemMap.unmap(MapBase, NewMapBase - MapBase);
569564
MapBase = NewMapBase;
570565
}
571566
const uptr NewMapEnd =
572567
CommitBase + PageSize + roundUp(Size, PageSize) + PageSize;
573568
DCHECK_LE(NewMapEnd, MapEnd);
574569
if (SCUDO_WORDSIZE == 32U && NewMapEnd != MapEnd) {
575-
unmap(reinterpret_cast<void *>(NewMapEnd), MapEnd - NewMapEnd, 0, &Data);
570+
MemMap.unmap(NewMapEnd, MapEnd - NewMapEnd);
576571
MapEnd = NewMapEnd;
577572
}
578573
}
579574

580575
const uptr CommitSize = MapEnd - PageSize - CommitBase;
581576
const uptr AllocPos = roundDown(CommitBase + CommitSize - Size, Alignment);
582-
mapSecondary<Config>(Options, CommitBase, CommitSize, AllocPos, 0, &Data);
577+
mapSecondary<Config>(Options, CommitBase, CommitSize, AllocPos, 0, MemMap);
583578
const uptr HeaderPos =
584579
AllocPos - Chunk::getHeaderSize() - LargeBlock::getHeaderSize();
585580
LargeBlock::Header *H = reinterpret_cast<LargeBlock::Header *>(
586581
LargeBlock::addHeaderTag<Config>(HeaderPos));
587582
if (useMemoryTagging<Config>(Options))
588583
storeTags(LargeBlock::addHeaderTag<Config>(CommitBase),
589584
reinterpret_cast<uptr>(H + 1));
590-
H->MapBase = MapBase;
591-
H->MapSize = MapEnd - MapBase;
592585
H->CommitBase = CommitBase;
593586
H->CommitSize = CommitSize;
594-
H->Data = Data;
587+
H->MemMap = MemMap;
595588
if (BlockEndPtr)
596589
*BlockEndPtr = CommitBase + CommitSize;
597590
{
@@ -602,7 +595,7 @@ void *MapAllocator<Config>::allocate(Options Options, uptr Size, uptr Alignment,
602595
LargestSize = CommitSize;
603596
NumberOfAllocs++;
604597
Stats.add(StatAllocated, CommitSize);
605-
Stats.add(StatMapped, H->MapSize);
598+
Stats.add(StatMapped, H->MemMap.getCapacity());
606599
}
607600
return reinterpret_cast<void *>(HeaderPos + LargeBlock::getHeaderSize());
608601
}
@@ -618,7 +611,7 @@ void MapAllocator<Config>::deallocate(Options Options, void *Ptr)
618611
FreedBytes += CommitSize;
619612
NumberOfFrees++;
620613
Stats.sub(StatAllocated, CommitSize);
621-
Stats.sub(StatMapped, H->MapSize);
614+
Stats.sub(StatMapped, H->MemMap.getCapacity());
622615
}
623616
Cache.store(Options, H);
624617
}

0 commit comments

Comments
 (0)