Skip to content

Commit 46044a6

Browse files
committed
[gwp-asan] Implement malloc_iterate.
Summary: This is an Android-specific interface for iterating over all live allocations in a memory range. Reviewers: hctim, cferris Subscribers: mgorny, mgrang, #sanitizers, llvm-commits Tags: #sanitizers, #llvm Differential Revision: https://reviews.llvm.org/D73305
1 parent cbbbd5b commit 46044a6

File tree

5 files changed

+87
-0
lines changed

5 files changed

+87
-0
lines changed

compiler-rt/lib/gwp_asan/guarded_pool_allocator.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,17 @@ void GuardedPoolAllocator::disable() { PoolMutex.lock(); }
182182

183183
void GuardedPoolAllocator::enable() { PoolMutex.unlock(); }
184184

185+
void GuardedPoolAllocator::iterate(void *Base, size_t Size, iterate_callback Cb,
186+
void *Arg) {
187+
uintptr_t Start = reinterpret_cast<uintptr_t>(Base);
188+
for (size_t i = 0; i < MaxSimultaneousAllocations; ++i) {
189+
const AllocationMetadata &Meta = Metadata[i];
190+
if (Meta.Addr && !Meta.IsDeallocated && Meta.Addr >= Start &&
191+
Meta.Addr < Start + Size)
192+
Cb(Meta.Addr, Meta.Size, Arg);
193+
}
194+
}
195+
185196
void GuardedPoolAllocator::uninitTestOnly() {
186197
if (GuardedPagePool) {
187198
unmapMemory(reinterpret_cast<void *>(GuardedPagePool),

compiler-rt/lib/gwp_asan/guarded_pool_allocator.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,12 @@ class GuardedPoolAllocator {
106106
void disable();
107107
void enable();
108108

109+
typedef void (*iterate_callback)(uintptr_t base, size_t size, void *arg);
110+
// Execute the callback Cb for every allocation the lies in [Base, Base + Size).
111+
// Must be called while the allocator is disabled. The callback can not
112+
// allocate.
113+
void iterate(void *Base, size_t Size, iterate_callback Cb, void *Arg);
114+
109115
// Return whether the allocation should be randomly chosen for sampling.
110116
GWP_ASAN_ALWAYS_INLINE bool shouldSample() {
111117
// NextSampleCounter == 0 means we "should regenerate the counter".

compiler-rt/lib/gwp_asan/tests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ set(GWP_ASAN_UNITTESTS
1414
backtrace.cpp
1515
basic.cpp
1616
compression.cpp
17+
iterate.cpp
1718
driver.cpp
1819
mutex_test.cpp
1920
slot_reuse.cpp
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
//===-- iterate.cpp ---------------------------------------------*- 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+
#include "gwp_asan/tests/harness.h"
10+
11+
TEST_F(CustomGuardedPoolAllocator, Iterate) {
12+
InitNumSlots(7);
13+
std::vector<std::pair<void *, size_t>> Allocated;
14+
auto alloc = [&](size_t size) {
15+
Allocated.push_back({GPA.allocate(size), size});
16+
};
17+
18+
void *Ptr = GPA.allocate(5);
19+
alloc(2);
20+
alloc(1);
21+
alloc(100);
22+
GPA.deallocate(Ptr);
23+
alloc(42);
24+
std::sort(Allocated.begin(), Allocated.end());
25+
26+
GPA.disable();
27+
void *Base = Allocated[0].first;
28+
size_t Size = reinterpret_cast<size_t>(Allocated.back().first) -
29+
reinterpret_cast<size_t>(Base) + 1;
30+
std::vector<std::pair<void *, size_t>> Found;
31+
GPA.iterate(
32+
Base, Size,
33+
[](uintptr_t Addr, size_t Size, void *Arg) {
34+
reinterpret_cast<std::vector<std::pair<void *, size_t>> *>(Arg)
35+
->push_back({(void *)Addr, Size});
36+
},
37+
reinterpret_cast<void *>(&Found));
38+
GPA.enable();
39+
40+
std::sort(Found.begin(), Found.end());
41+
EXPECT_EQ(Allocated, Found);
42+
43+
// Now without the last allocation.
44+
GPA.disable();
45+
Size = reinterpret_cast<size_t>(Allocated.back().first) -
46+
reinterpret_cast<size_t>(Base); // Allocated.back() is out of range.
47+
Found.clear();
48+
GPA.iterate(
49+
Base, Size,
50+
[](uintptr_t Addr, size_t Size, void *Arg) {
51+
reinterpret_cast<std::vector<std::pair<void *, size_t>> *>(Arg)
52+
->push_back({(void *)Addr, Size});
53+
},
54+
reinterpret_cast<void *>(&Found));
55+
GPA.enable();
56+
57+
// We should have found every allocation but the last.
58+
// Remove it and compare the rest.
59+
std::sort(Found.begin(), Found.end());
60+
GPA.deallocate(Allocated.back().first);
61+
Allocated.pop_back();
62+
EXPECT_EQ(Allocated, Found);
63+
64+
for (auto PS : Allocated)
65+
GPA.deallocate(PS.first);
66+
}

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -592,6 +592,9 @@ class Allocator {
592592
};
593593
Primary.iterateOverBlocks(Lambda);
594594
Secondary.iterateOverBlocks(Lambda);
595+
#ifdef GWP_ASAN_HOOKS
596+
GuardedAlloc.iterate(reinterpret_cast<void *>(Base), Size, Callback, Arg);
597+
#endif
595598
}
596599

597600
bool canReturnNull() {

0 commit comments

Comments
 (0)