PRCYCoin  2.0.0.7rc1
P2P Digital Currency
allocators.h
Go to the documentation of this file.
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2013 The Bitcoin developers
3 // Distributed under the MIT/X11 software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 
6 #ifndef BITCOIN_ALLOCATORS_H
7 #define BITCOIN_ALLOCATORS_H
8 
9 #include "support/cleanse.h"
10 
11 #include <map>
12 #include <string.h>
13 #include <string>
14 #include <vector>
15 
16 #include <boost/thread/mutex.hpp>
17 #include <boost/thread/once.hpp>
18 
30 template <class Locker>
32 {
33 public:
35  {
36  // Determine bitmask for extracting page from address
37  assert(!(page_size & (page_size - 1))); // size must be power of two
38  page_mask = ~(page_size - 1);
39  }
40 
42  {
43  }
44 
45 
46  // For all pages in affected range, increase lock count
47  void LockRange(void* p, size_t size)
48  {
49  boost::mutex::scoped_lock lock(mutex);
50  if (!size)
51  return;
52  const size_t base_addr = reinterpret_cast<size_t>(p);
53  const size_t start_page = base_addr & page_mask;
54  const size_t end_page = (base_addr + size - 1) & page_mask;
55  for (size_t page = start_page; page <= end_page; page += page_size) {
56  Histogram::iterator it = histogram.find(page);
57  if (it == histogram.end()) // Newly locked page
58  {
59  locker.Lock(reinterpret_cast<void*>(page), page_size);
60  histogram.insert(std::make_pair(page, 1));
61  } else // Page was already locked; increase counter
62  {
63  it->second += 1;
64  }
65  }
66  }
67 
68  // For all pages in affected range, decrease lock count
69  void UnlockRange(void* p, size_t size)
70  {
71  boost::mutex::scoped_lock lock(mutex);
72  if (!size)
73  return;
74  const size_t base_addr = reinterpret_cast<size_t>(p);
75  const size_t start_page = base_addr & page_mask;
76  const size_t end_page = (base_addr + size - 1) & page_mask;
77  for (size_t page = start_page; page <= end_page; page += page_size) {
78  Histogram::iterator it = histogram.find(page);
79  assert(it != histogram.end()); // Cannot unlock an area that was not locked
80  // Decrease counter for page, when it is zero, the page will be unlocked
81  it->second -= 1;
82  if (it->second == 0) // Nothing on the page anymore that keeps it locked
83  {
84  // Unlock page and remove the count from histogram
85  locker.Unlock(reinterpret_cast<void*>(page), page_size);
86  histogram.erase(it);
87  }
88  }
89  }
90 
91  // Get number of locked pages for diagnostics
93  {
94  boost::mutex::scoped_lock lock(mutex);
95  return histogram.size();
96  }
97 
98 private:
99  Locker locker;
100  boost::mutex mutex;
102  // map of page base address to lock count
103  typedef std::map<size_t, int> Histogram;
105 };
106 
107 
113 {
114 public:
118  bool Lock(const void* addr, size_t len);
122  bool Unlock(const void* addr, size_t len);
123 };
124 
136 class LockedPageManager : public LockedPageManagerBase<MemoryPageLocker>
137 {
138 public:
140  {
143  }
144 
145 private:
147 
148  static void CreateInstance()
149  {
150  // Using a local static instance guarantees that the object is initialized
151  // when it's first needed and also deinitialized after all objects that use
152  // it are done with it. I can think of one unlikely scenario where we may
153  // have a static deinitialization order/problem, but the check in
154  // LockedPageManagerBase's destructor helps us detect if that ever happens.
155  static LockedPageManager instance;
156  LockedPageManager::_instance = &instance;
157  }
158 
160  static boost::once_flag init_flag;
161 };
162 
163 //
164 // Functions for directly locking/unlocking memory objects.
165 // Intended for non-dynamically allocated structures.
166 //
167 template <typename T>
168 void LockObject(const T& t)
169 {
170  LockedPageManager::Instance().LockRange((void*)(&t), sizeof(T));
171 }
172 
173 template <typename T>
174 void UnlockObject(const T& t)
175 {
176  memory_cleanse((void*)(&t), sizeof(T));
177  LockedPageManager::Instance().UnlockRange((void*)(&t), sizeof(T));
178 }
179 
180 //
181 // Allocator that locks its contents from being paged
182 // out of memory and clears its contents before deletion.
183 //
184 template <typename T>
185 struct secure_allocator : public std::allocator<T> {
186  // MSVC8 default copy constructor is broken
187  typedef std::allocator<T> base;
188  typedef typename base::size_type size_type;
189  typedef typename base::difference_type difference_type;
190  typedef typename base::pointer pointer;
191  typedef typename base::const_pointer const_pointer;
192  typedef typename base::reference reference;
193  typedef typename base::const_reference const_reference;
194  typedef typename base::value_type value_type;
195  secure_allocator() noexcept {}
196  secure_allocator(const secure_allocator& a) noexcept : base(a) {}
197  template <typename U>
198  secure_allocator(const secure_allocator<U>& a) noexcept : base(a)
199  {
200  }
201  ~secure_allocator() noexcept {}
202  template <typename _Other>
203  struct rebind {
205  };
206 
207  T* allocate(std::size_t n, const void* hint = 0)
208  {
209  T* p;
210  p = std::allocator<T>::allocate(n, hint);
211  if (p != NULL)
212  LockedPageManager::Instance().LockRange(p, sizeof(T) * n);
213  return p;
214  }
215 
216  void deallocate(T* p, std::size_t n)
217  {
218  if (p != NULL) {
219  memory_cleanse(p, sizeof(T) * n);
220  LockedPageManager::Instance().UnlockRange(p, sizeof(T) * n);
221  }
222  std::allocator<T>::deallocate(p, n);
223  }
224 };
225 
226 
227 //
228 // Allocator that clears its contents before deletion.
229 //
230 template <typename T>
231 struct zero_after_free_allocator : public std::allocator<T> {
232  // MSVC8 default copy constructor is broken
233  typedef std::allocator<T> base;
234  typedef typename base::size_type size_type;
235  typedef typename base::difference_type difference_type;
236  typedef typename base::pointer pointer;
237  typedef typename base::const_pointer const_pointer;
238  typedef typename base::reference reference;
239  typedef typename base::const_reference const_reference;
240  typedef typename base::value_type value_type;
243  template <typename U>
245  {
246  }
248  template <typename _Other>
249  struct rebind {
251  };
252 
253  void deallocate(T* p, std::size_t n)
254  {
255  if (p != NULL)
256  memory_cleanse(p, sizeof(T) * n);
257  std::allocator<T>::deallocate(p, n);
258  }
259 };
260 
261 // This is exactly like std::string, but with a custom allocator.
262 typedef std::basic_string<char, std::char_traits<char>, secure_allocator<char> > SecureString;
263 
264 // Byte-vector that clears its contents before deletion.
265 typedef std::vector<char, zero_after_free_allocator<char> > CSerializeData;
266 
267 typedef std::vector<unsigned char, secure_allocator<unsigned char> > SecureVector;
268 
269 #endif // BITCOIN_ALLOCATORS_H
UnlockObject
void UnlockObject(const T &t)
Definition: allocators.h:174
zero_after_free_allocator::reference
base::reference reference
Definition: allocators.h:238
LockedPageManagerBase::UnlockRange
void UnlockRange(void *p, size_t size)
Definition: allocators.h:69
secure_allocator::reference
base::reference reference
Definition: allocators.h:192
secure_allocator::secure_allocator
secure_allocator(const secure_allocator< U > &a) noexcept
Definition: allocators.h:198
LockedPageManager::init_flag
static boost::once_flag init_flag
Definition: allocators.h:160
secure_allocator::secure_allocator
secure_allocator() noexcept
Definition: allocators.h:195
secure_allocator
Definition: allocators.h:185
zero_after_free_allocator::const_pointer
base::const_pointer const_pointer
Definition: allocators.h:237
secure_allocator::~secure_allocator
~secure_allocator() noexcept
Definition: allocators.h:201
LockedPageManager::CreateInstance
static void CreateInstance()
Definition: allocators.h:148
zero_after_free_allocator::pointer
base::pointer pointer
Definition: allocators.h:236
LockedPageManagerBase::page_mask
size_t page_mask
Definition: allocators.h:101
LockedPageManagerBase::LockedPageManagerBase
LockedPageManagerBase(size_t page_size)
Definition: allocators.h:34
LockedPageManager
Singleton class to keep track of locked (ie, non-swappable) memory pages, for use in std::allocator t...
Definition: allocators.h:136
zero_after_free_allocator::~zero_after_free_allocator
~zero_after_free_allocator() noexcept
Definition: allocators.h:247
LockedPageManagerBase
Thread-safe class to keep track of locked (ie, non-swappable) memory pages.
Definition: allocators.h:31
LockedPageManagerBase::GetLockedPageCount
int GetLockedPageCount()
Definition: allocators.h:92
zero_after_free_allocator::value_type
base::value_type value_type
Definition: allocators.h:240
MemoryPageLocker::Unlock
bool Unlock(const void *addr, size_t len)
Unlock memory pages.
Definition: allocators.cpp:50
memory_cleanse
void memory_cleanse(void *ptr, size_t len)
Definition: cleanse.cpp:27
LockedPageManagerBase::page_size
size_t page_size
Definition: allocators.h:101
secure_allocator::size_type
base::size_type size_type
Definition: allocators.h:188
secure_allocator::base
std::allocator< T > base
Definition: allocators.h:187
MemoryPageLocker::Lock
bool Lock(const void *addr, size_t len)
Lock memory pages.
Definition: allocators.cpp:41
LockedPageManagerBase::~LockedPageManagerBase
~LockedPageManagerBase()
Definition: allocators.h:41
secure_allocator::const_pointer
base::const_pointer const_pointer
Definition: allocators.h:191
secure_allocator::difference_type
base::difference_type difference_type
Definition: allocators.h:189
zero_after_free_allocator::rebind
Definition: allocators.h:249
LockedPageManager::LockedPageManager
LockedPageManager()
Definition: allocators.cpp:59
zero_after_free_allocator
Definition: allocators.h:231
cleanse.h
LockObject
void LockObject(const T &t)
Definition: allocators.h:168
SecureString
std::basic_string< char, std::char_traits< char >, secure_allocator< char > > SecureString
Definition: allocators.h:262
LockedPageManagerBase::mutex
boost::mutex mutex
Definition: allocators.h:100
CSerializeData
std::vector< char, zero_after_free_allocator< char > > CSerializeData
Definition: allocators.h:265
secure_allocator::rebind
Definition: allocators.h:203
zero_after_free_allocator::const_reference
base::const_reference const_reference
Definition: allocators.h:239
secure_allocator::value_type
base::value_type value_type
Definition: allocators.h:194
zero_after_free_allocator::size_type
base::size_type size_type
Definition: allocators.h:234
LockedPageManagerBase::Histogram
std::map< size_t, int > Histogram
Definition: allocators.h:103
LockedPageManagerBase::locker
Locker locker
Definition: allocators.h:99
secure_allocator::rebind::other
secure_allocator< _Other > other
Definition: allocators.h:204
LockedPageManager::_instance
static LockedPageManager * _instance
Definition: allocators.h:159
zero_after_free_allocator::zero_after_free_allocator
zero_after_free_allocator() noexcept
Definition: allocators.h:241
secure_allocator::allocate
T * allocate(std::size_t n, const void *hint=0)
Definition: allocators.h:207
SecureVector
std::vector< unsigned char, secure_allocator< unsigned char > > SecureVector
Definition: allocators.h:267
LockedPageManagerBase::histogram
Histogram histogram
Definition: allocators.h:104
MemoryPageLocker
OS-dependent memory page locking/unlocking.
Definition: allocators.h:112
zero_after_free_allocator::zero_after_free_allocator
zero_after_free_allocator(const zero_after_free_allocator< U > &a) noexcept
Definition: allocators.h:244
zero_after_free_allocator::deallocate
void deallocate(T *p, std::size_t n)
Definition: allocators.h:253
LockedPageManager::Instance
static LockedPageManager & Instance()
Definition: allocators.h:139
zero_after_free_allocator::rebind::other
zero_after_free_allocator< _Other > other
Definition: allocators.h:250
zero_after_free_allocator::zero_after_free_allocator
zero_after_free_allocator(const zero_after_free_allocator &a) noexcept
Definition: allocators.h:242
secure_allocator::deallocate
void deallocate(T *p, std::size_t n)
Definition: allocators.h:216
zero_after_free_allocator::base
std::allocator< T > base
Definition: allocators.h:233
secure_allocator::secure_allocator
secure_allocator(const secure_allocator &a) noexcept
Definition: allocators.h:196
secure_allocator::const_reference
base::const_reference const_reference
Definition: allocators.h:193
zero_after_free_allocator::difference_type
base::difference_type difference_type
Definition: allocators.h:235
secure_allocator::pointer
base::pointer pointer
Definition: allocators.h:190
LockedPageManagerBase::LockRange
void LockRange(void *p, size_t size)
Definition: allocators.h:47