You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

allocators.h 8.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  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. #ifndef BITCOIN_ALLOCATORS_H
  6. #define BITCOIN_ALLOCATORS_H
  7. #include <map>
  8. #include <string>
  9. #include <string.h>
  10. #include <boost/thread/mutex.hpp>
  11. #include <boost/thread/once.hpp>
  12. #include <openssl/crypto.h> // for OPENSSL_cleanse()
  13. /**
  14. * Thread-safe class to keep track of locked (ie, non-swappable) memory pages.
  15. *
  16. * Memory locks do not stack, that is, pages which have been locked several times by calls to mlock()
  17. * will be unlocked by a single call to munlock(). This can result in keying material ending up in swap when
  18. * those functions are used naively. This class simulates stacking memory locks by keeping a counter per page.
  19. *
  20. * @note By using a map from each page base address to lock count, this class is optimized for
  21. * small objects that span up to a few pages, mostly smaller than a page. To support large allocations,
  22. * something like an interval tree would be the preferred data structure.
  23. */
  24. template <class Locker> class LockedPageManagerBase
  25. {
  26. public:
  27. LockedPageManagerBase(size_t page_size):
  28. page_size(page_size)
  29. {
  30. // Determine bitmask for extracting page from address
  31. assert(!(page_size & (page_size-1))); // size must be power of two
  32. page_mask = ~(page_size - 1);
  33. }
  34. ~LockedPageManagerBase()
  35. {
  36. assert(this->GetLockedPageCount() == 0);
  37. }
  38. // For all pages in affected range, increase lock count
  39. void LockRange(void *p, size_t size)
  40. {
  41. boost::mutex::scoped_lock lock(mutex);
  42. if(!size) return;
  43. const size_t base_addr = reinterpret_cast<size_t>(p);
  44. const size_t start_page = base_addr & page_mask;
  45. const size_t end_page = (base_addr + size - 1) & page_mask;
  46. for(size_t page = start_page; page <= end_page; page += page_size)
  47. {
  48. Histogram::iterator it = histogram.find(page);
  49. if(it == histogram.end()) // Newly locked page
  50. {
  51. locker.Lock(reinterpret_cast<void*>(page), page_size);
  52. histogram.insert(std::make_pair(page, 1));
  53. }
  54. else // Page was already locked; increase counter
  55. {
  56. it->second += 1;
  57. }
  58. }
  59. }
  60. // For all pages in affected range, decrease lock count
  61. void UnlockRange(void *p, size_t size)
  62. {
  63. boost::mutex::scoped_lock lock(mutex);
  64. if(!size) return;
  65. const size_t base_addr = reinterpret_cast<size_t>(p);
  66. const size_t start_page = base_addr & page_mask;
  67. const size_t end_page = (base_addr + size - 1) & page_mask;
  68. for(size_t page = start_page; page <= end_page; page += page_size)
  69. {
  70. Histogram::iterator it = histogram.find(page);
  71. assert(it != histogram.end()); // Cannot unlock an area that was not locked
  72. // Decrease counter for page, when it is zero, the page will be unlocked
  73. it->second -= 1;
  74. if(it->second == 0) // Nothing on the page anymore that keeps it locked
  75. {
  76. // Unlock page and remove the count from histogram
  77. locker.Unlock(reinterpret_cast<void*>(page), page_size);
  78. histogram.erase(it);
  79. }
  80. }
  81. }
  82. // Get number of locked pages for diagnostics
  83. int GetLockedPageCount()
  84. {
  85. boost::mutex::scoped_lock lock(mutex);
  86. return histogram.size();
  87. }
  88. private:
  89. Locker locker;
  90. boost::mutex mutex;
  91. size_t page_size, page_mask;
  92. // map of page base address to lock count
  93. typedef std::map<size_t,int> Histogram;
  94. Histogram histogram;
  95. };
  96. /**
  97. * OS-dependent memory page locking/unlocking.
  98. * Defined as policy class to make stubbing for test possible.
  99. */
  100. class MemoryPageLocker
  101. {
  102. public:
  103. /** Lock memory pages.
  104. * addr and len must be a multiple of the system page size
  105. */
  106. bool Lock(const void *addr, size_t len);
  107. /** Unlock memory pages.
  108. * addr and len must be a multiple of the system page size
  109. */
  110. bool Unlock(const void *addr, size_t len);
  111. };
  112. /**
  113. * Singleton class to keep track of locked (ie, non-swappable) memory pages, for use in
  114. * std::allocator templates.
  115. *
  116. * Some implementations of the STL allocate memory in some constructors (i.e., see
  117. * MSVC's vector<T> implementation where it allocates 1 byte of memory in the allocator.)
  118. * Due to the unpredictable order of static initializers, we have to make sure the
  119. * LockedPageManager instance exists before any other STL-based objects that use
  120. * secure_allocator are created. So instead of having LockedPageManager also be
  121. * static-intialized, it is created on demand.
  122. */
  123. class LockedPageManager: public LockedPageManagerBase<MemoryPageLocker>
  124. {
  125. public:
  126. static LockedPageManager& Instance()
  127. {
  128. boost::call_once(LockedPageManager::CreateInstance, LockedPageManager::init_flag);
  129. return *LockedPageManager::_instance;
  130. }
  131. private:
  132. LockedPageManager();
  133. static void CreateInstance()
  134. {
  135. // Using a local static instance guarantees that the object is initialized
  136. // when it's first needed and also deinitialized after all objects that use
  137. // it are done with it. I can think of one unlikely scenario where we may
  138. // have a static deinitialization order/problem, but the check in
  139. // LockedPageManagerBase's destructor helps us detect if that ever happens.
  140. static LockedPageManager instance;
  141. LockedPageManager::_instance = &instance;
  142. }
  143. static LockedPageManager* _instance;
  144. static boost::once_flag init_flag;
  145. };
  146. //
  147. // Functions for directly locking/unlocking memory objects.
  148. // Intended for non-dynamically allocated structures.
  149. //
  150. template<typename T> void LockObject(const T &t) {
  151. LockedPageManager::Instance().LockRange((void*)(&t), sizeof(T));
  152. }
  153. template<typename T> void UnlockObject(const T &t) {
  154. OPENSSL_cleanse((void*)(&t), sizeof(T));
  155. LockedPageManager::Instance().UnlockRange((void*)(&t), sizeof(T));
  156. }
  157. //
  158. // Allocator that locks its contents from being paged
  159. // out of memory and clears its contents before deletion.
  160. //
  161. template<typename T>
  162. struct secure_allocator : public std::allocator<T>
  163. {
  164. // MSVC8 default copy constructor is broken
  165. typedef std::allocator<T> base;
  166. typedef typename base::size_type size_type;
  167. typedef typename base::difference_type difference_type;
  168. typedef typename base::pointer pointer;
  169. typedef typename base::const_pointer const_pointer;
  170. typedef typename base::reference reference;
  171. typedef typename base::const_reference const_reference;
  172. typedef typename base::value_type value_type;
  173. secure_allocator() throw() {}
  174. secure_allocator(const secure_allocator& a) throw() : base(a) {}
  175. template <typename U>
  176. secure_allocator(const secure_allocator<U>& a) throw() : base(a) {}
  177. ~secure_allocator() throw() {}
  178. template<typename _Other> struct rebind
  179. { typedef secure_allocator<_Other> other; };
  180. T* allocate(std::size_t n, const void *hint = 0)
  181. {
  182. T *p;
  183. p = std::allocator<T>::allocate(n, hint);
  184. if (p != NULL)
  185. LockedPageManager::Instance().LockRange(p, sizeof(T) * n);
  186. return p;
  187. }
  188. void deallocate(T* p, std::size_t n)
  189. {
  190. if (p != NULL)
  191. {
  192. OPENSSL_cleanse(p, sizeof(T) * n);
  193. LockedPageManager::Instance().UnlockRange(p, sizeof(T) * n);
  194. }
  195. std::allocator<T>::deallocate(p, n);
  196. }
  197. };
  198. //
  199. // Allocator that clears its contents before deletion.
  200. //
  201. template<typename T>
  202. struct zero_after_free_allocator : public std::allocator<T>
  203. {
  204. // MSVC8 default copy constructor is broken
  205. typedef std::allocator<T> base;
  206. typedef typename base::size_type size_type;
  207. typedef typename base::difference_type difference_type;
  208. typedef typename base::pointer pointer;
  209. typedef typename base::const_pointer const_pointer;
  210. typedef typename base::reference reference;
  211. typedef typename base::const_reference const_reference;
  212. typedef typename base::value_type value_type;
  213. zero_after_free_allocator() throw() {}
  214. zero_after_free_allocator(const zero_after_free_allocator& a) throw() : base(a) {}
  215. template <typename U>
  216. zero_after_free_allocator(const zero_after_free_allocator<U>& a) throw() : base(a) {}
  217. ~zero_after_free_allocator() throw() {}
  218. template<typename _Other> struct rebind
  219. { typedef zero_after_free_allocator<_Other> other; };
  220. void deallocate(T* p, std::size_t n)
  221. {
  222. if (p != NULL)
  223. OPENSSL_cleanse(p, sizeof(T) * n);
  224. std::allocator<T>::deallocate(p, n);
  225. }
  226. };
  227. // This is exactly like std::string, but with a custom allocator.
  228. typedef std::basic_string<char, std::char_traits<char>, secure_allocator<char> > SecureString;
  229. #endif