Botan 3.11.0
Crypto and TLS for C&
Botan::Memory_Pool Class Referencefinal

#include <mem_pool.h>

Public Member Functions

void * allocate (size_t size)
bool deallocate (void *p, size_t size) noexcept
 Memory_Pool (const Memory_Pool &)=delete
 Memory_Pool (const std::vector< void * > &pages, size_t page_size) noexcept
 Memory_Pool (Memory_Pool &&)=delete
Memory_Pooloperator= (const Memory_Pool &)=delete
Memory_Pooloperator= (Memory_Pool &&)=delete
 ~Memory_Pool () noexcept

Detailed Description

Definition at line 20 of file mem_pool.h.

Constructor & Destructor Documentation

◆ Memory_Pool() [1/3]

Botan::Memory_Pool::Memory_Pool ( const std::vector< void * > & pages,
size_t page_size )
noexcept

Initialize a memory pool. The memory is not owned by *this, it must be freed by the caller.

Parameters
pagesa list of pages to allocate from
page_sizethe system page size, each page should point to exactly this much memory.

Definition at line 293 of file mem_pool.cpp.

293 : m_page_size(page_size) {
294 for(auto* page : pages) {
295 const uintptr_t p = reinterpret_cast<uintptr_t>(page);
296
297 m_min_page_ptr = std::min(p, m_min_page_ptr);
298 m_max_page_ptr = std::max(p, m_max_page_ptr);
299
300 clear_bytes(page, m_page_size);
301#if defined(BOTAN_MEM_POOL_USE_MMU_PROTECTIONS)
303#endif
304 m_free_pages.push_back(static_cast<uint8_t*>(page));
305 }
306
307 /*
308 Right now this points to the start of the last page, adjust it to instead
309 point to the first byte of the following page
310 */
311 m_max_page_ptr += page_size;
312}
void page_prohibit_access(void *page)
Definition os_utils.cpp:627
constexpr void clear_bytes(void *ptr, size_t bytes)
Definition mem_ops.h:101

References Botan::clear_bytes(), and Botan::OS::page_prohibit_access().

Referenced by Memory_Pool(), Memory_Pool(), operator=(), and operator=().

◆ ~Memory_Pool()

Botan::Memory_Pool::~Memory_Pool ( )
noexcept

Definition at line 314 of file mem_pool.cpp.

315{
316#if defined(BOTAN_MEM_POOL_USE_MMU_PROTECTIONS)
317 for(size_t i = 0; i != m_free_pages.size(); ++i) {
318 OS::page_allow_access(m_free_pages[i]);
319 }
320#endif
321}
void page_allow_access(void *page)
Definition os_utils.cpp:613

References Botan::OS::page_allow_access().

◆ Memory_Pool() [2/3]

Botan::Memory_Pool::Memory_Pool ( const Memory_Pool & )
delete

References Memory_Pool().

◆ Memory_Pool() [3/3]

Botan::Memory_Pool::Memory_Pool ( Memory_Pool && )
delete

References Memory_Pool().

Member Function Documentation

◆ allocate()

void * Botan::Memory_Pool::allocate ( size_t size)

Definition at line 323 of file mem_pool.cpp.

323 {
324 if(n > m_page_size) {
325 return nullptr;
326 }
327
328 const size_t n_bucket = choose_bucket(n);
329
330 if(n_bucket > 0) {
331 const lock_guard_type<mutex_type> lock(m_mutex);
332
333 std::deque<Bucket>& buckets = m_buckets_for[n_bucket];
334
335 /*
336 It would be optimal to pick the bucket with the most usage,
337 since a bucket with say 1 item allocated out of it has a high
338 chance of becoming later freed and then the whole page can be
339 recycled.
340 */
341 for(auto& bucket : buckets) {
342 // NOLINTNEXTLINE(*-const-correctness) bug in clang-tidy
343 if(uint8_t* p = bucket.alloc()) {
344 return p;
345 }
346
347 // If the bucket is full, maybe move it to the end of the list?
348 // Otoh bucket search should be very fast
349 }
350
351 if(!m_free_pages.empty()) {
352 uint8_t* ptr = m_free_pages[0];
353 m_free_pages.pop_front();
354#if defined(BOTAN_MEM_POOL_USE_MMU_PROTECTIONS)
356#endif
357 buckets.push_front(Bucket(ptr, m_page_size, n_bucket));
358 // NOLINTNEXTLINE(*-const-correctness) bug in clang-tidy
359 void* p = buckets[0].alloc();
360 BOTAN_ASSERT_NOMSG(p != nullptr);
361 return p;
362 }
363 }
364
365 // out of room
366 return nullptr;
367}
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:75
secure_vector< T > lock(const std::vector< T > &in)
Definition secmem.h:80
lock_guard< T > lock_guard_type
Definition mutex.h:55

References BOTAN_ASSERT_NOMSG, Botan::lock(), and Botan::OS::page_allow_access().

◆ deallocate()

bool Botan::Memory_Pool::deallocate ( void * p,
size_t size )
noexcept

Definition at line 369 of file mem_pool.cpp.

369 {
370 // Do a fast range check first, before taking the lock
371 const uintptr_t p_val = reinterpret_cast<uintptr_t>(p);
372 if(p_val < m_min_page_ptr || p_val > m_max_page_ptr) {
373 return false;
374 }
375
376 const size_t n_bucket = choose_bucket(len);
377
378 if(n_bucket != 0) {
379 try {
380 const lock_guard_type<mutex_type> lock(m_mutex);
381
382 std::deque<Bucket>& buckets = m_buckets_for[n_bucket];
383
384 for(size_t i = 0; i != buckets.size(); ++i) {
385 Bucket& bucket = buckets[i];
386 if(bucket.free(p)) {
387 if(bucket.empty()) {
388#if defined(BOTAN_MEM_POOL_USE_MMU_PROTECTIONS)
389 OS::page_prohibit_access(bucket.ptr());
390#endif
391 m_free_pages.push_back(bucket.ptr());
392
393 if(i != buckets.size() - 1) {
394 std::swap(buckets.back(), buckets[i]);
395 }
396 buckets.pop_back();
397 }
398 return true;
399 }
400 }
401 } catch(...) {
402 /*
403 * The only exception throws that can occur in the above code are from
404 * either the STL or BOTAN_ASSERT failures. In either case, such an
405 * error indicates a logic error or data corruption in the memory
406 * allocator such that it is no longer safe to continue executing.
407 *
408 * Since this function is noexcept, simply letting the exception escape
409 * is sufficient for terminate to be called. However in this scenario
410 * it is implementation defined if any stack unwinding is performed.
411 * Since stack unwinding could cause further memory deallocations this
412 * could result in further corruption in this allocator state. To prevent
413 * this, call terminate directly.
414 */
415 std::terminate();
416 }
417 }
418
419 return false;
420}

References Botan::lock(), and Botan::OS::page_prohibit_access().

◆ operator=() [1/2]

Memory_Pool & Botan::Memory_Pool::operator= ( const Memory_Pool & )
delete

References Memory_Pool().

◆ operator=() [2/2]

Memory_Pool & Botan::Memory_Pool::operator= ( Memory_Pool && )
delete

References Memory_Pool().


The documentation for this class was generated from the following files: