Master Core  v0.0.9 - 2abfd2849db8ba7a83957c64eb976b406713c123
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
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 <map>
10 #include <string>
11 #include <string.h>
12 
13 #include <boost/thread/mutex.hpp>
14 #include <boost/thread/once.hpp>
15 #include <openssl/crypto.h> // for OPENSSL_cleanse()
16 
28 template <class Locker> class LockedPageManagerBase
29 {
30 public:
32  page_size(page_size)
33  {
34  // Determine bitmask for extracting page from address
35  assert(!(page_size & (page_size-1))); // size must be power of two
36  page_mask = ~(page_size - 1);
37  }
38 
40  {
41  assert(this->GetLockedPageCount() == 0);
42  }
43 
44 
45  // For all pages in affected range, increase lock count
46  void LockRange(void *p, size_t size)
47  {
48  boost::mutex::scoped_lock lock(mutex);
49  if(!size) return;
50  const size_t base_addr = reinterpret_cast<size_t>(p);
51  const size_t start_page = base_addr & page_mask;
52  const size_t end_page = (base_addr + size - 1) & page_mask;
53  for(size_t page = start_page; page <= end_page; page += page_size)
54  {
55  Histogram::iterator it = histogram.find(page);
56  if(it == histogram.end()) // Newly locked page
57  {
58  locker.Lock(reinterpret_cast<void*>(page), page_size);
59  histogram.insert(std::make_pair(page, 1));
60  }
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) return;
73  const size_t base_addr = reinterpret_cast<size_t>(p);
74  const size_t start_page = base_addr & page_mask;
75  const size_t end_page = (base_addr + size - 1) & page_mask;
76  for(size_t page = start_page; page <= end_page; page += page_size)
77  {
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;
104  Histogram 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> void LockObject(const T &t) {
168  LockedPageManager::Instance().LockRange((void*)(&t), sizeof(T));
169 }
170 
171 template<typename T> void UnlockObject(const T &t) {
172  OPENSSL_cleanse((void*)(&t), sizeof(T));
173  LockedPageManager::Instance().UnlockRange((void*)(&t), sizeof(T));
174 }
175 
176 //
177 // Allocator that locks its contents from being paged
178 // out of memory and clears its contents before deletion.
179 //
180 template<typename T>
181 struct secure_allocator : public std::allocator<T>
182 {
183  // MSVC8 default copy constructor is broken
184  typedef std::allocator<T> base;
185  typedef typename base::size_type size_type;
186  typedef typename base::difference_type difference_type;
187  typedef typename base::pointer pointer;
188  typedef typename base::const_pointer const_pointer;
189  typedef typename base::reference reference;
190  typedef typename base::const_reference const_reference;
191  typedef typename base::value_type value_type;
192  secure_allocator() throw() {}
193  secure_allocator(const secure_allocator& a) throw() : base(a) {}
194  template <typename U>
195  secure_allocator(const secure_allocator<U>& a) throw() : base(a) {}
196  ~secure_allocator() throw() {}
197  template<typename _Other> struct rebind
199 
200  T* allocate(std::size_t n, const void *hint = 0)
201  {
202  T *p;
203  p = std::allocator<T>::allocate(n, hint);
204  if (p != NULL)
205  LockedPageManager::Instance().LockRange(p, sizeof(T) * n);
206  return p;
207  }
208 
209  void deallocate(T* p, std::size_t n)
210  {
211  if (p != NULL)
212  {
213  OPENSSL_cleanse(p, sizeof(T) * n);
214  LockedPageManager::Instance().UnlockRange(p, sizeof(T) * n);
215  }
216  std::allocator<T>::deallocate(p, n);
217  }
218 };
219 
220 
221 //
222 // Allocator that clears its contents before deletion.
223 //
224 template<typename T>
225 struct zero_after_free_allocator : public std::allocator<T>
226 {
227  // MSVC8 default copy constructor is broken
228  typedef std::allocator<T> base;
229  typedef typename base::size_type size_type;
230  typedef typename base::difference_type difference_type;
231  typedef typename base::pointer pointer;
232  typedef typename base::const_pointer const_pointer;
233  typedef typename base::reference reference;
234  typedef typename base::const_reference const_reference;
235  typedef typename base::value_type value_type;
238  template <typename U>
241  template<typename _Other> struct rebind
243 
244  void deallocate(T* p, std::size_t n)
245  {
246  if (p != NULL)
247  OPENSSL_cleanse(p, sizeof(T) * n);
248  std::allocator<T>::deallocate(p, n);
249  }
250 };
251 
252 // This is exactly like std::string, but with a custom allocator.
253 typedef std::basic_string<char, std::char_traits<char>, secure_allocator<char> > SecureString;
254 
255 #endif
void UnlockObject(const T &t)
Definition: allocators.h:171
base::const_reference const_reference
Definition: allocators.h:190
secure_allocator(const secure_allocator &a)
Definition: allocators.h:193
LockedPageManagerBase(size_t page_size)
Definition: allocators.h:31
base::pointer pointer
Definition: allocators.h:187
void LockRange(void *p, size_t size)
Definition: allocators.h:46
Thread-safe class to keep track of locked (ie, non-swappable) memory pages.
Definition: allocators.h:28
base::const_pointer const_pointer
Definition: allocators.h:232
base::size_type size_type
Definition: allocators.h:185
boost::mutex mutex
Definition: allocators.h:100
static boost::once_flag init_flag
Definition: allocators.h:160
base::value_type value_type
Definition: allocators.h:191
base::value_type value_type
Definition: allocators.h:235
secure_allocator< _Other > other
Definition: allocators.h:198
bool Unlock(const void *addr, size_t len)
Unlock memory pages.
Definition: allocators.cpp:55
void LockObject(const T &t)
Definition: allocators.h:167
static void CreateInstance()
Definition: allocators.h:148
std::map< size_t, int > Histogram
Definition: allocators.h:103
zero_after_free_allocator< _Other > other
Definition: allocators.h:242
base::const_reference const_reference
Definition: allocators.h:234
std::basic_string< char, std::char_traits< char >, secure_allocator< char > > SecureString
Definition: allocators.h:253
base::reference reference
Definition: allocators.h:189
Singleton class to keep track of locked (ie, non-swappable) memory pages, for use in std::allocator t...
Definition: allocators.h:136
secure_allocator(const secure_allocator< U > &a)
Definition: allocators.h:195
std::allocator< T > base
Definition: allocators.h:184
static LockedPageManager & Instance()
Definition: allocators.h:139
OS-dependent memory page locking/unlocking.
Definition: allocators.h:112
base::const_pointer const_pointer
Definition: allocators.h:188
zero_after_free_allocator(const zero_after_free_allocator &a)
Definition: allocators.h:237
base::size_type size_type
Definition: allocators.h:229
zero_after_free_allocator(const zero_after_free_allocator< U > &a)
Definition: allocators.h:239
void UnlockRange(void *p, size_t size)
Definition: allocators.h:69
T * allocate(std::size_t n, const void *hint=0)
Definition: allocators.h:200
base::difference_type difference_type
Definition: allocators.h:186
std::allocator< T > base
Definition: allocators.h:228
static LockedPageManager * _instance
Definition: allocators.h:159
void deallocate(T *p, std::size_t n)
Definition: allocators.h:244
base::difference_type difference_type
Definition: allocators.h:230
void deallocate(T *p, std::size_t n)
Definition: allocators.h:209
base::reference reference
Definition: allocators.h:233
bool Lock(const void *addr, size_t len)
Lock memory pages.
Definition: allocators.cpp:46