Skip to content

Commit ad13276

Browse files
committed
[allocators] Apply manual ASan poisoning to PoolResource
1 parent 87ec923 commit ad13276

File tree

3 files changed

+32
-1
lines changed

3 files changed

+32
-1
lines changed

src/support/allocators/pool.h

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
#include <type_traits>
1515
#include <utility>
1616

17+
#include <util/check.h>
18+
1719
/**
1820
* A memory resource similar to std::pmr::unsynchronized_pool_resource, but
1921
* optimized for node-based containers. It has the following properties:
@@ -155,12 +157,15 @@ class PoolResource final
155157
// if there is still any available memory left, put it into the freelist.
156158
size_t remaining_available_bytes = std::distance(m_available_memory_it, m_available_memory_end);
157159
if (0 != remaining_available_bytes) {
160+
ASAN_UNPOISON_MEMORY_REGION(m_available_memory_it, sizeof(ListNode));
158161
PlacementAddToList(m_available_memory_it, m_free_lists[remaining_available_bytes / ELEM_ALIGN_BYTES]);
162+
ASAN_POISON_MEMORY_REGION(m_available_memory_it, sizeof(ListNode));
159163
}
160164

161165
void* storage = ::operator new (m_chunk_size_bytes, std::align_val_t{ELEM_ALIGN_BYTES});
162166
m_available_memory_it = new (storage) std::byte[m_chunk_size_bytes];
163167
m_available_memory_end = m_available_memory_it + m_chunk_size_bytes;
168+
ASAN_POISON_MEMORY_REGION(m_available_memory_it, m_chunk_size_bytes);
164169
m_allocated_chunks.emplace_back(m_available_memory_it);
165170
}
166171

@@ -202,6 +207,7 @@ class PoolResource final
202207
for (std::byte* chunk : m_allocated_chunks) {
203208
std::destroy(chunk, chunk + m_chunk_size_bytes);
204209
::operator delete ((void*)chunk, std::align_val_t{ELEM_ALIGN_BYTES});
210+
ASAN_UNPOISON_MEMORY_REGION(chunk, m_chunk_size_bytes);
205211
}
206212
}
207213

@@ -217,7 +223,11 @@ class PoolResource final
217223
// we've already got data in the pool's freelist, unlink one element and return the pointer
218224
// to the unlinked memory. Since FreeList is trivially destructible we can just treat it as
219225
// uninitialized memory.
220-
return std::exchange(m_free_lists[num_alignments], m_free_lists[num_alignments]->m_next);
226+
ASAN_UNPOISON_MEMORY_REGION(m_free_lists[num_alignments], sizeof(ListNode));
227+
auto* next{m_free_lists[num_alignments]->m_next};
228+
ASAN_POISON_MEMORY_REGION(m_free_lists[num_alignments], sizeof(ListNode));
229+
ASAN_UNPOISON_MEMORY_REGION(m_free_lists[num_alignments], bytes);
230+
return std::exchange(m_free_lists[num_alignments], next);
221231
}
222232

223233
// freelist is empty: get one allocation from allocated chunk memory.
@@ -228,6 +238,7 @@ class PoolResource final
228238
}
229239

230240
// Make sure we use the right amount of bytes for that freelist (might be rounded up),
241+
ASAN_UNPOISON_MEMORY_REGION(m_available_memory_it, round_bytes);
231242
return std::exchange(m_available_memory_it, m_available_memory_it + round_bytes);
232243
}
233244

@@ -244,7 +255,9 @@ class PoolResource final
244255
const std::size_t num_alignments = NumElemAlignBytes(bytes);
245256
// put the memory block into the linked list. We can placement construct the FreeList
246257
// into the memory since we can be sure the alignment is correct.
258+
ASAN_UNPOISON_MEMORY_REGION(p, sizeof(ListNode));
247259
PlacementAddToList(p, m_free_lists[num_alignments]);
260+
ASAN_POISON_MEMORY_REGION(p, std::max(bytes, sizeof(ListNode)));
248261
} else {
249262
// Can't use the pool => forward deallocation to ::operator delete().
250263
::operator delete (p, std::align_val_t{alignment});

src/test/util/poolresourcetester.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#define BITCOIN_TEST_UTIL_POOLRESOURCETESTER_H
77

88
#include <support/allocators/pool.h>
9+
#include <util/check.h>
910

1011
#include <algorithm>
1112
#include <cassert>
@@ -48,7 +49,10 @@ class PoolResourceTester
4849
size_t size = 0;
4950
while (ptr != nullptr) {
5051
++size;
52+
const auto* ptr_ = ptr;
53+
ASAN_UNPOISON_MEMORY_REGION(ptr_, sizeof(typename PoolResource<MAX_BLOCK_SIZE_BYTES, ALIGN_BYTES>::ListNode));
5154
ptr = ptr->m_next;
55+
ASAN_POISON_MEMORY_REGION(ptr_, sizeof(typename PoolResource<MAX_BLOCK_SIZE_BYTES, ALIGN_BYTES>::ListNode));
5256
}
5357
sizes.push_back(size);
5458
}
@@ -81,7 +85,10 @@ class PoolResourceTester
8185
auto* ptr = resource.m_free_lists[freelist_idx];
8286
while (ptr != nullptr) {
8387
free_blocks.emplace_back(ptr, bytes);
88+
const auto* ptr_ = ptr;
89+
ASAN_UNPOISON_MEMORY_REGION(ptr_, sizeof(typename PoolResource<MAX_BLOCK_SIZE_BYTES, ALIGN_BYTES>::ListNode));
8490
ptr = ptr->m_next;
91+
ASAN_POISON_MEMORY_REGION(ptr_, sizeof(typename PoolResource<MAX_BLOCK_SIZE_BYTES, ALIGN_BYTES>::ListNode));
8592
}
8693
}
8794
// also add whatever has not yet been used for blocks

src/util/check.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,4 +126,15 @@ constexpr T&& inline_assertion_check(LIFETIMEBOUND T&& val, [[maybe_unused]] con
126126

127127
// NOLINTEND(bugprone-lambda-function-name)
128128

129+
#if defined(__has_feature)
130+
# if __has_feature(address_sanitizer)
131+
# include <sanitizer/asan_interface.h>
132+
# endif
133+
#endif
134+
135+
#ifndef ASAN_POISON_MEMORY_REGION
136+
# define ASAN_POISON_MEMORY_REGION(addr, size) ((void)(addr), (void)(size))
137+
# define ASAN_UNPOISON_MEMORY_REGION(addr, size) ((void)(addr), (void)(size))
138+
#endif
139+
129140
#endif // BITCOIN_UTIL_CHECK_H

0 commit comments

Comments
 (0)