From a0b04c18d3bc6716af9844de00944b455e728599 Mon Sep 17 00:00:00 2001 From: Alexander Block Date: Wed, 2 Jun 2021 15:59:16 +0200 Subject: [PATCH] Add pooled_secure_allocator and mt_pooled_secure_allocator --- src/Makefile.am | 2 + src/support/allocators/mt_pooled_secure.h | 86 +++++++++++++++++++++++ src/support/allocators/pooled_secure.h | 72 +++++++++++++++++++ 3 files changed, 160 insertions(+) create mode 100644 src/support/allocators/mt_pooled_secure.h create mode 100644 src/support/allocators/pooled_secure.h diff --git a/src/Makefile.am b/src/Makefile.am index 06b0726745217..47f67cb155613 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -276,6 +276,8 @@ BITCOIN_CORE_H = \ stakeinput.h \ script/ismine.h \ streams.h \ + support/allocators/mt_pooled_secure.h \ + support/allocators/pooled_secure.h \ support/allocators/secure.h \ support/allocators/zeroafterfree.h \ support/cleanse.h \ diff --git a/src/support/allocators/mt_pooled_secure.h b/src/support/allocators/mt_pooled_secure.h new file mode 100644 index 0000000000000..56f6cdc2f2ec1 --- /dev/null +++ b/src/support/allocators/mt_pooled_secure.h @@ -0,0 +1,86 @@ +// Copyright (c) 2018-2021 The Dash Core developers +// Copyright (c) 2021 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef PIVX_SUPPORT_ALLOCATORS_MT_POOLED_SECURE_H +#define PIVX_SUPPORT_ALLOCATORS_MT_POOLED_SECURE_H + +#include "pooled_secure.h" + +#include +#include + +// +// Manages a pool of pools to balance allocation between those when multiple threads are involved +// This allocator is fully thread safe +// +template +struct mt_pooled_secure_allocator : public std::allocator { + // MSVC8 default copy constructor is broken + typedef std::allocator base; + typedef typename base::size_type size_type; + typedef typename base::difference_type difference_type; + typedef typename base::pointer pointer; + typedef typename base::const_pointer const_pointer; + typedef typename base::reference reference; + typedef typename base::const_reference const_reference; + typedef typename base::value_type value_type; + mt_pooled_secure_allocator(size_type nrequested_size = 32, + size_type nnext_size = 32, + size_type nmax_size = 0) throw() + { + // we add enough bytes to the requested size so that we can store the bucket as well + nrequested_size += sizeof(size_t); + + size_t pools_count = std::thread::hardware_concurrency(); + pools.resize(pools_count); + for (size_t i = 0; i < pools_count; i++) { + pools[i] = std::make_unique(nrequested_size, nnext_size, nmax_size); + } + } + ~mt_pooled_secure_allocator() throw() {} + + T* allocate(std::size_t n, const void* hint = 0) + { + size_t bucket = get_bucket(); + std::lock_guard lock(pools[bucket]->mutex); + uint8_t* ptr = pools[bucket]->allocate(n * sizeof(T) + sizeof(size_t)); + *(size_t*)ptr = bucket; + return static_cast(ptr + sizeof(size_t)); + } + + void deallocate(T* p, std::size_t n) + { + if (!p) { + return; + } + uint8_t* ptr = (uint8_t*)p - sizeof(size_t); + size_t bucket = *(size_t*)ptr; + std::lock_guard lock(pools[bucket]->mutex); + pools[bucket]->deallocate(ptr, n * sizeof(T)); + } + +private: + size_t get_bucket() + { + auto tid = std::this_thread::get_id(); + size_t x = std::hash{}(std::this_thread::get_id()); + return x % pools.size(); + } + + struct internal_pool : pooled_secure_allocator { + internal_pool(size_type nrequested_size, + size_type nnext_size, + size_type nmax_size) : + pooled_secure_allocator(nrequested_size, nnext_size, nmax_size) + { + } + std::mutex mutex; + }; + +private: + std::vector> pools; +}; + +#endif // PIVX_SUPPORT_ALLOCATORS_MT_POOLED_SECURE_H diff --git a/src/support/allocators/pooled_secure.h b/src/support/allocators/pooled_secure.h new file mode 100644 index 0000000000000..37b967f2ab3f2 --- /dev/null +++ b/src/support/allocators/pooled_secure.h @@ -0,0 +1,72 @@ +// Copyright (c) 2018-2021 The Dash Core developers +// Copyright (c) 2021 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef PIVX_SUPPORT_ALLOCATORS_POOLED_SECURE_H +#define PIVX_SUPPORT_ALLOCATORS_POOLED_SECURE_H + +#include "support/lockedpool.h" +#include "support/cleanse.h" + +#include +#include + +#include + +// +// Allocator that allocates memory in chunks from a pool, which in turn allocates larger chunks from secure memory +// Memory is cleaned when freed as well. This allocator is NOT thread safe +// +template +struct pooled_secure_allocator : public std::allocator { + // MSVC8 default copy constructor is broken + typedef std::allocator base; + typedef typename base::size_type size_type; + typedef typename base::difference_type difference_type; + typedef typename base::pointer pointer; + typedef typename base::const_pointer const_pointer; + typedef typename base::reference reference; + typedef typename base::const_reference const_reference; + typedef typename base::value_type value_type; + pooled_secure_allocator(const size_type nrequested_size = 32, + const size_type nnext_size = 32, + const size_type nmax_size = 0) throw() : + pool(nrequested_size, nnext_size, nmax_size){} + ~pooled_secure_allocator() throw() {} + + T* allocate(std::size_t n, const void* hint = 0) + { + size_t chunks = (n * sizeof(T) + pool.get_requested_size() - 1) / pool.get_requested_size(); + return static_cast(pool.ordered_malloc(chunks)); + } + + void deallocate(T* p, std::size_t n) + { + size_t chunks = (n * sizeof(T) + pool.get_requested_size() - 1) / pool.get_requested_size(); + if (p != NULL) { + memory_cleanse(p, chunks * pool.get_requested_size()); + } + pool.ordered_free(p, chunks); + } + +public: + struct internal_secure_allocator { + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + static char* malloc(const size_type bytes) + { + return static_cast(LockedPoolManager::Instance().alloc(bytes)); + } + + static void free(char* const block) + { + LockedPoolManager::Instance().free(block); + } + }; +private: + boost::pool pool; +}; + +#endif // PIVX_SUPPORT_ALLOCATORS_POOLED_SECURE_H