Skip to content

Commit

Permalink
Add pooled_secure_allocator and mt_pooled_secure_allocator
Browse files Browse the repository at this point in the history
  • Loading branch information
codablock authored and random-zebra committed Sep 14, 2021
1 parent dbb0305 commit a0b04c1
Show file tree
Hide file tree
Showing 3 changed files with 160 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand Down
86 changes: 86 additions & 0 deletions src/support/allocators/mt_pooled_secure.h
Original file line number Diff line number Diff line change
@@ -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 <thread>
#include <mutex>

//
// Manages a pool of pools to balance allocation between those when multiple threads are involved
// This allocator is fully thread safe
//
template <typename T>
struct mt_pooled_secure_allocator : public std::allocator<T> {
// MSVC8 default copy constructor is broken
typedef std::allocator<T> 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<internal_pool>(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<std::mutex> lock(pools[bucket]->mutex);
uint8_t* ptr = pools[bucket]->allocate(n * sizeof(T) + sizeof(size_t));
*(size_t*)ptr = bucket;
return static_cast<T*>(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<std::mutex> 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::thread::id>{}(std::this_thread::get_id());
return x % pools.size();
}

struct internal_pool : pooled_secure_allocator<uint8_t> {
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<std::unique_ptr<internal_pool>> pools;
};

#endif // PIVX_SUPPORT_ALLOCATORS_MT_POOLED_SECURE_H
72 changes: 72 additions & 0 deletions src/support/allocators/pooled_secure.h
Original file line number Diff line number Diff line change
@@ -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 <string>
#include <vector>

#include <boost/pool/pool_alloc.hpp>

//
// 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 <typename T>
struct pooled_secure_allocator : public std::allocator<T> {
// MSVC8 default copy constructor is broken
typedef std::allocator<T> 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<T*>(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<char*>(LockedPoolManager::Instance().alloc(bytes));
}

static void free(char* const block)
{
LockedPoolManager::Instance().free(block);
}
};
private:
boost::pool<internal_secure_allocator> pool;
};

#endif // PIVX_SUPPORT_ALLOCATORS_POOLED_SECURE_H

0 comments on commit a0b04c1

Please sign in to comment.