Feathercoin  0.5.0
P2P Digital Currency
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros
allocators.h
Go to the documentation of this file.
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2012 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 #ifndef BITCOIN_ALLOCATORS_H
6 #define BITCOIN_ALLOCATORS_H
7 
8 #include <string.h>
9 #include <string>
10 #include <boost/thread/mutex.hpp>
11 #include <map>
12 #include <openssl/crypto.h> // for OPENSSL_cleanse()
13 
14 #ifdef WIN32
15 #ifdef _WIN32_WINNT
16 #undef _WIN32_WINNT
17 #endif
18 #define _WIN32_WINNT 0x0501
19 #define WIN32_LEAN_AND_MEAN 1
20 #ifndef NOMINMAX
21 #define NOMINMAX
22 #endif
23 #include <windows.h>
24 // This is used to attempt to keep keying material out of swap
25 // Note that VirtualLock does not provide this as a guarantee on Windows,
26 // but, in practice, memory that has been VirtualLock'd almost never gets written to
27 // the pagefile except in rare circumstances where memory is extremely low.
28 #else
29 #include <sys/mman.h>
30 #include <limits.h> // for PAGESIZE
31 #include <unistd.h> // for sysconf
32 #endif
33 
45 template <class Locker> class LockedPageManagerBase
46 {
47 public:
49  page_size(page_size)
50  {
51  // Determine bitmask for extracting page from address
52  assert(!(page_size & (page_size-1))); // size must be power of two
53  page_mask = ~(page_size - 1);
54  }
55 
56  // For all pages in affected range, increase lock count
57  void LockRange(void *p, size_t size)
58  {
59  boost::mutex::scoped_lock lock(mutex);
60  if(!size) return;
61  const size_t base_addr = reinterpret_cast<size_t>(p);
62  const size_t start_page = base_addr & page_mask;
63  const size_t end_page = (base_addr + size - 1) & page_mask;
64  for(size_t page = start_page; page <= end_page; page += page_size)
65  {
66  Histogram::iterator it = histogram.find(page);
67  if(it == histogram.end()) // Newly locked page
68  {
69  locker.Lock(reinterpret_cast<void*>(page), page_size);
70  histogram.insert(std::make_pair(page, 1));
71  }
72  else // Page was already locked; increase counter
73  {
74  it->second += 1;
75  }
76  }
77  }
78 
79  // For all pages in affected range, decrease lock count
80  void UnlockRange(void *p, size_t size)
81  {
82  boost::mutex::scoped_lock lock(mutex);
83  if(!size) return;
84  const size_t base_addr = reinterpret_cast<size_t>(p);
85  const size_t start_page = base_addr & page_mask;
86  const size_t end_page = (base_addr + size - 1) & page_mask;
87  for(size_t page = start_page; page <= end_page; page += page_size)
88  {
89  Histogram::iterator it = histogram.find(page);
90  assert(it != histogram.end()); // Cannot unlock an area that was not locked
91  // Decrease counter for page, when it is zero, the page will be unlocked
92  it->second -= 1;
93  if(it->second == 0) // Nothing on the page anymore that keeps it locked
94  {
95  // Unlock page and remove the count from histogram
96  locker.Unlock(reinterpret_cast<void*>(page), page_size);
97  histogram.erase(it);
98  }
99  }
100  }
101 
102  // Get number of locked pages for diagnostics
104  {
105  boost::mutex::scoped_lock lock(mutex);
106  return histogram.size();
107  }
108 
109 private:
110  Locker locker;
111  boost::mutex mutex;
113  // map of page base address to lock count
114  typedef std::map<size_t,int> Histogram;
115  Histogram histogram;
116 };
117 
119 static inline size_t GetSystemPageSize()
120 {
121  size_t page_size;
122 #if defined(WIN32)
123  SYSTEM_INFO sSysInfo;
124  GetSystemInfo(&sSysInfo);
125  page_size = sSysInfo.dwPageSize;
126 #elif defined(PAGESIZE) // defined in limits.h
127  page_size = PAGESIZE;
128 #else // assume some POSIX OS
129  page_size = sysconf(_SC_PAGESIZE);
130 #endif
131  return page_size;
132 }
133 
139 {
140 public:
144  bool Lock(const void *addr, size_t len)
145  {
146 #ifdef WIN32
147  return VirtualLock(const_cast<void*>(addr), len);
148 #else
149  return mlock(addr, len) == 0;
150 #endif
151  }
155  bool Unlock(const void *addr, size_t len)
156  {
157 #ifdef WIN32
158  return VirtualUnlock(const_cast<void*>(addr), len);
159 #else
160  return munlock(addr, len) == 0;
161 #endif
162  }
163 };
164 
169 class LockedPageManager: public LockedPageManagerBase<MemoryPageLocker>
170 {
171 public:
172  static LockedPageManager instance; // instantiated in util.cpp
173 private:
175  LockedPageManagerBase<MemoryPageLocker>(GetSystemPageSize())
176  {}
177 };
178 
179 //
180 // Functions for directly locking/unlocking memory objects.
181 // Intended for non-dynamically allocated structures.
182 //
183 template<typename T> void LockObject(const T &t) {
184  LockedPageManager::instance.LockRange((void*)(&t), sizeof(T));
185 }
186 
187 template<typename T> void UnlockObject(const T &t) {
188  OPENSSL_cleanse((void*)(&t), sizeof(T));
189  LockedPageManager::instance.UnlockRange((void*)(&t), sizeof(T));
190 }
191 
192 //
193 // Allocator that locks its contents from being paged
194 // out of memory and clears its contents before deletion.
195 //
196 template<typename T>
197 struct secure_allocator : public std::allocator<T>
198 {
199  // MSVC8 default copy constructor is broken
200  typedef std::allocator<T> base;
201  typedef typename base::size_type size_type;
202  typedef typename base::difference_type difference_type;
203  typedef typename base::pointer pointer;
204  typedef typename base::const_pointer const_pointer;
205  typedef typename base::reference reference;
206  typedef typename base::const_reference const_reference;
207  typedef typename base::value_type value_type;
208  secure_allocator() throw() {}
209  secure_allocator(const secure_allocator& a) throw() : base(a) {}
210  template <typename U>
211  secure_allocator(const secure_allocator<U>& a) throw() : base(a) {}
212  ~secure_allocator() throw() {}
213  template<typename _Other> struct rebind
215 
216  T* allocate(std::size_t n, const void *hint = 0)
217  {
218  T *p;
219  p = std::allocator<T>::allocate(n, hint);
220  if (p != NULL)
221  LockedPageManager::instance.LockRange(p, sizeof(T) * n);
222  return p;
223  }
224 
225  void deallocate(T* p, std::size_t n)
226  {
227  if (p != NULL)
228  {
229  OPENSSL_cleanse(p, sizeof(T) * n);
230  LockedPageManager::instance.UnlockRange(p, sizeof(T) * n);
231  }
232  std::allocator<T>::deallocate(p, n);
233  }
234 };
235 
236 
237 //
238 // Allocator that clears its contents before deletion.
239 //
240 template<typename T>
241 struct zero_after_free_allocator : public std::allocator<T>
242 {
243  // MSVC8 default copy constructor is broken
244  typedef std::allocator<T> base;
245  typedef typename base::size_type size_type;
246  typedef typename base::difference_type difference_type;
247  typedef typename base::pointer pointer;
248  typedef typename base::const_pointer const_pointer;
249  typedef typename base::reference reference;
250  typedef typename base::const_reference const_reference;
251  typedef typename base::value_type value_type;
254  template <typename U>
257  template<typename _Other> struct rebind
259 
260  void deallocate(T* p, std::size_t n)
261  {
262  if (p != NULL)
263  OPENSSL_cleanse(p, sizeof(T) * n);
264  std::allocator<T>::deallocate(p, n);
265  }
266 };
267 
268 // This is exactly like std::string, but with a custom allocator.
269 typedef std::basic_string<char, std::char_traits<char>, secure_allocator<char> > SecureString;
270 
271 #endif
void UnlockObject(const T &t)
Definition: allocators.h:187
base::const_reference const_reference
Definition: allocators.h:206
secure_allocator(const secure_allocator &a)
Definition: allocators.h:209
LockedPageManagerBase(size_t page_size)
Definition: allocators.h:48
base::pointer pointer
Definition: allocators.h:203
static LockedPageManager instance
Definition: allocators.h:172
void LockRange(void *p, size_t size)
Definition: allocators.h:57
Thread-safe class to keep track of locked (ie, non-swappable) memory pages.
Definition: allocators.h:45
base::const_pointer const_pointer
Definition: allocators.h:248
base::size_type size_type
Definition: allocators.h:201
boost::mutex mutex
Definition: allocators.h:111
base::value_type value_type
Definition: allocators.h:207
base::value_type value_type
Definition: allocators.h:251
secure_allocator< _Other > other
Definition: allocators.h:214
bool Unlock(const void *addr, size_t len)
Unlock memory pages.
Definition: allocators.h:155
void LockObject(const T &t)
Definition: allocators.h:183
std::map< size_t, int > Histogram
Definition: allocators.h:114
zero_after_free_allocator< _Other > other
Definition: allocators.h:258
base::const_reference const_reference
Definition: allocators.h:250
std::basic_string< char, std::char_traits< char >, secure_allocator< char > > SecureString
Definition: allocators.h:269
base::reference reference
Definition: allocators.h:205
Singleton class to keep track of locked (ie, non-swappable) memory pages, for use in std::allocator t...
Definition: allocators.h:169
secure_allocator(const secure_allocator< U > &a)
Definition: allocators.h:211
std::allocator< T > base
Definition: allocators.h:200
OS-dependent memory page locking/unlocking.
Definition: allocators.h:138
base::const_pointer const_pointer
Definition: allocators.h:204
zero_after_free_allocator(const zero_after_free_allocator &a)
Definition: allocators.h:253
base::size_type size_type
Definition: allocators.h:245
zero_after_free_allocator(const zero_after_free_allocator< U > &a)
Definition: allocators.h:255
void UnlockRange(void *p, size_t size)
Definition: allocators.h:80
T * allocate(std::size_t n, const void *hint=0)
Definition: allocators.h:216
base::difference_type difference_type
Definition: allocators.h:202
std::allocator< T > base
Definition: allocators.h:244
void deallocate(T *p, std::size_t n)
Definition: allocators.h:260
base::difference_type difference_type
Definition: allocators.h:246
void deallocate(T *p, std::size_t n)
Definition: allocators.h:225
base::reference reference
Definition: allocators.h:249
bool Lock(const void *addr, size_t len)
Lock memory pages.
Definition: allocators.h:144