Botan  2.4.0
Crypto and TLS for C++11
Public Member Functions | Static Public Member Functions | List of all members
Botan::mlock_allocator Class Referencefinal

#include <locking_allocator.h>

Public Member Functions

void * allocate (size_t num_elems, size_t elem_size)
 
bool deallocate (void *p, size_t num_elems, size_t elem_size) BOTAN_NOEXCEPT
 
 mlock_allocator (const mlock_allocator &)=delete
 
mlock_allocatoroperator= (const mlock_allocator &)=delete
 

Static Public Member Functions

static mlock_allocatorinstance ()
 

Detailed Description

Definition at line 17 of file locking_allocator.h.

Constructor & Destructor Documentation

◆ mlock_allocator()

Botan::mlock_allocator::mlock_allocator ( const mlock_allocator )
delete

Member Function Documentation

◆ allocate()

void * Botan::mlock_allocator::allocate ( size_t  num_elems,
size_t  elem_size 
)

Definition at line 38 of file locking_allocator.cpp.

References BOTAN_ASSERT, and Botan::clear_mem().

39  {
40  if(!m_pool)
41  return nullptr;
42 
43  const size_t n = num_elems * elem_size;
44  const size_t alignment = 16;
45 
46  if(n / elem_size != num_elems)
47  return nullptr; // overflow!
48 
49  if(n > m_poolsize)
50  return nullptr;
51  if(n < BOTAN_MLOCK_ALLOCATOR_MIN_ALLOCATION || n > BOTAN_MLOCK_ALLOCATOR_MAX_ALLOCATION)
52  return nullptr;
53 
54  lock_guard_type<mutex_type> lock(m_mutex);
55 
56  auto best_fit = m_freelist.end();
57 
58  for(auto i = m_freelist.begin(); i != m_freelist.end(); ++i)
59  {
60  // If we have a perfect fit, use it immediately
61  if(i->second == n && (i->first % alignment) == 0)
62  {
63  const size_t offset = i->first;
64  m_freelist.erase(i);
65  clear_mem(m_pool + offset, n);
66 
67  BOTAN_ASSERT((reinterpret_cast<uintptr_t>(m_pool) + offset) % alignment == 0,
68  "Returning correctly aligned pointer");
69 
70  return m_pool + offset;
71  }
72 
73  if((i->second >= (n + padding_for_alignment(i->first, alignment)) &&
74  ((best_fit == m_freelist.end()) || (best_fit->second > i->second))))
75  {
76  best_fit = i;
77  }
78  }
79 
80  if(best_fit != m_freelist.end())
81  {
82  const size_t offset = best_fit->first;
83 
84  const size_t alignment_padding = padding_for_alignment(offset, alignment);
85 
86  best_fit->first += n + alignment_padding;
87  best_fit->second -= n + alignment_padding;
88 
89  // Need to realign, split the block
90  if(alignment_padding)
91  {
92  /*
93  If we used the entire block except for small piece used for
94  alignment at the beginning, so just update the entry already
95  in place (as it is in the correct location), rather than
96  deleting the empty range and inserting the new one in the
97  same location.
98  */
99  if(best_fit->second == 0)
100  {
101  best_fit->first = offset;
102  best_fit->second = alignment_padding;
103  }
104  else
105  m_freelist.insert(best_fit, std::make_pair(offset, alignment_padding));
106  }
107 
108  clear_mem(m_pool + offset + alignment_padding, n);
109 
110  BOTAN_ASSERT((reinterpret_cast<uintptr_t>(m_pool) + offset + alignment_padding) % alignment == 0,
111  "Returning correctly aligned pointer");
112 
113  return m_pool + offset + alignment_padding;
114  }
115 
116  return nullptr;
117  }
void clear_mem(T *ptr, size_t n)
Definition: mem_ops.h:86
#define BOTAN_ASSERT(expr, assertion_made)
Definition: assert.h:29

◆ deallocate()

bool Botan::mlock_allocator::deallocate ( void *  p,
size_t  num_elems,
size_t  elem_size 
)

Definition at line 119 of file locking_allocator.cpp.

References Botan::OS::allocate_locked_pages(), Botan::OS::free_locked_pages(), Botan::OS::get_memory_locking_limit(), and Botan::secure_scrub_memory().

120  {
121  if(!m_pool)
122  return false;
123 
124  size_t n = num_elems * elem_size;
125 
126  /*
127  We return nullptr in allocate if there was an overflow, so if an
128  overflow occurs here we know the pointer was not allocated by this pool.
129  */
130  if(n / elem_size != num_elems)
131  return false;
132 
133  if(!ptr_in_pool(m_pool, m_poolsize, p, n))
134  return false;
135 
136  std::memset(p, 0, n);
137 
138  lock_guard_type<mutex_type> lock(m_mutex);
139 
140  const size_t start = static_cast<uint8_t*>(p) - m_pool;
141 
142  auto comp = [](std::pair<size_t, size_t> x, std::pair<size_t, size_t> y){ return x.first < y.first; };
143 
144  auto i = std::lower_bound(m_freelist.begin(), m_freelist.end(),
145  std::make_pair(start, 0), comp);
146 
147  // try to merge with later block
148  if(i != m_freelist.end() && start + n == i->first)
149  {
150  i->first = start;
151  i->second += n;
152  n = 0;
153  }
154 
155  // try to merge with previous block
156  if(i != m_freelist.begin())
157  {
158  auto prev = std::prev(i);
159 
160  if(prev->first + prev->second == start)
161  {
162  if(n)
163  {
164  prev->second += n;
165  n = 0;
166  }
167  else
168  {
169  // merge adjoining
170  prev->second += i->second;
171  m_freelist.erase(i);
172  }
173  }
174  }
175 
176  if(n != 0) // no merge possible?
177  m_freelist.insert(i, std::make_pair(start, n));
178 
179  return true;
180  }

◆ instance()

mlock_allocator & Botan::mlock_allocator::instance ( )
static

Definition at line 214 of file locking_allocator.cpp.

Referenced by Botan::allocate_memory(), and Botan::deallocate_memory().

215  {
216  static mlock_allocator mlock;
217  return mlock;
218  }
mlock_allocator(const mlock_allocator &)=delete

◆ operator=()

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

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