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