Create allocatorc.cpp file
authorsvost <ya.nowa@yandex.ru>
Tue, 15 Feb 2022 19:15:22 +0000 (22:15 +0300)
committersvost <ya.nowa@yandex.ru>
Tue, 15 Feb 2022 19:15:22 +0000 (22:15 +0300)
CMakeLists.txt
src/CMakeLists.txt
src/allocators.cpp [new file with mode: 0644]
src/allocators.h
src/crypter.h
src/util.cpp

index 8746d69..036024d 100644 (file)
@@ -110,6 +110,7 @@ set(generic_sources
     ${CMAKE_CURRENT_SOURCE_DIR}/src/qt/mintingfilterproxy.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/src/qt/mintingtablemodel.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/src/qt/mintingview.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/src/allocators.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/src/bignum.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/src/coincontrol.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/src/kernelrecord.cpp
index a088b3f..74969fe 100644 (file)
@@ -78,6 +78,7 @@ endif()
 set(generic_sources 
     ${CMAKE_CURRENT_SOURCE_DIR}/addrman.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/alert.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/allocators.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/base58.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/bignum.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/bitcoinrpc.cpp
diff --git a/src/allocators.cpp b/src/allocators.cpp
new file mode 100644 (file)
index 0000000..5e3ac7f
--- /dev/null
@@ -0,0 +1,65 @@
+// Copyright (c) 2009-2013 The Bitcoin developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include "allocators.h"
+
+#ifdef WIN32
+#if (_WIN32_WINNT != _WIN32_WINNT_WIN7)
+#define _WIN32_WINNT 0x601
+#endif
+#define WIN32_LEAN_AND_MEAN 1
+#ifndef NOMINMAX
+#define NOMINMAX
+#endif
+#include <windows.h>
+// This is used to attempt to keep keying material out of swap
+// Note that VirtualLock does not provide this as a guarantee on Windows,
+// but, in practice, memory that has been VirtualLock'd almost never gets written to
+// the pagefile except in rare circumstances where memory is extremely low.
+#else
+#include <sys/mman.h>
+#include <climits> // for PAGESIZE
+#include <unistd.h> // for sysconf
+#endif
+
+LockedPageManager* LockedPageManager::_instance = nullptr;
+std::once_flag LockedPageManager::init_flag{};
+
+/** Determine system page size in bytes */
+static inline size_t GetSystemPageSize()
+{
+    size_t page_size;
+#if defined(WIN32)
+    SYSTEM_INFO sSysInfo;
+    GetSystemInfo(&sSysInfo);
+    page_size = sSysInfo.dwPageSize;
+#elif defined(PAGESIZE) // defined in limits.h
+    page_size = PAGESIZE;
+#else // assume some POSIX OS
+    page_size = sysconf(_SC_PAGESIZE);
+#endif
+    return page_size;
+}
+
+bool MemoryPageLocker::Lock(const void *addr, size_t len)
+{
+#ifdef WIN32
+    return VirtualLock(const_cast<void*>(addr), len) != 0;
+#else
+    return mlock(addr, len) == 0;
+#endif
+}
+
+bool MemoryPageLocker::Unlock(const void *addr, size_t len)
+{
+#ifdef WIN32
+    return VirtualUnlock(const_cast<void*>(addr), len) != 0;
+#else
+    return munlock(addr, len) == 0;
+#endif
+}
+
+LockedPageManager::LockedPageManager(): LockedPageManagerBase<MemoryPageLocker>(GetSystemPageSize())
+{
+}
index 51bc73e..484d1b8 100644 (file)
 #include <map>
 #include <vector>
 
-#ifdef WIN32
-#if (_WIN32_WINNT != _WIN32_WINNT_WIN7)
-#define _WIN32_WINNT 0x601
-#endif
-#define WIN32_LEAN_AND_MEAN 1
-#ifndef NOMINMAX
-#define NOMINMAX
-#endif
-#include <windows.h>
-// This is used to attempt to keep keying material out of swap
-// Note that VirtualLock does not provide this as a guarantee on Windows,
-// but, in practice, memory that has been VirtualLock'd almost never gets written to
-// the pagefile except in rare circumstances where memory is extremely low.
-#else
-#include <sys/mman.h>
-#include <climits> // for PAGESIZE
-#include <unistd.h> // for sysconf
-#endif
-
 /**
  * Thread-safe class to keep track of locked (ie, non-swappable) memory pages.
  *
@@ -55,6 +36,11 @@ public:
         page_mask = ~(page_size - 1);
     }
 
+    ~LockedPageManagerBase()
+    {
+        assert(this->GetLockedPageCount() == 0);
+    }
+
     // For all pages in affected range, increase lock count
     void LockRange(void *p, size_t size)
     {
@@ -117,22 +103,6 @@ private:
     Histogram histogram;
 };
 
-/** Determine system page size in bytes */
-static inline size_t GetSystemPageSize()
-{
-    size_t page_size;
-#if defined(WIN32)
-    SYSTEM_INFO sSysInfo;
-    GetSystemInfo(&sSysInfo);
-    page_size = sSysInfo.dwPageSize;
-#elif defined(PAGESIZE) // defined in limits.h
-    page_size = PAGESIZE;
-#else // assume some POSIX OS
-    page_size = sysconf(_SC_PAGESIZE);
-#endif
-    return page_size;
-}
-
 /**
  * OS-dependent memory page locking/unlocking.
  * Defined as policy class to make stubbing for test possible.
@@ -143,39 +113,48 @@ public:
     /** Lock memory pages.
      * addr and len must be a multiple of the system page size
      */
-    bool Lock(const void *addr, size_t len)
-    {
-#ifdef WIN32
-        return VirtualLock(const_cast<void*>(addr), len) != 0;
-#else
-        return mlock(addr, len) == 0;
-#endif
-    }
+    bool Lock(const void *addr, size_t len);
     /** Unlock memory pages.
      * addr and len must be a multiple of the system page size
      */
-    bool Unlock(const void *addr, size_t len)
-    {
-#ifdef WIN32
-        return VirtualUnlock(const_cast<void*>(addr), len) != 0;
-#else
-        return munlock(addr, len) == 0;
-#endif
-    }
+    bool Unlock(const void *addr, size_t len);
 };
 
 /**
  * Singleton class to keep track of locked (ie, non-swappable) memory pages, for use in
  * std::allocator templates.
- */
+ *
+ * Some implementations of the STL allocate memory in some constructors (i.e., see
+ * MSVC's vector<T> implementation where it allocates 1 byte of memory in the allocator.)
+ * Due to the unpredictable order of static initializers, we have to make sure the
+ * LockedPageManager instance exists before any other STL-based objects that use
+ * secure_allocator are created. So instead of having LockedPageManager also be
+ * static-intialized, it is created on demand.
+*/
 class LockedPageManager: public LockedPageManagerBase<MemoryPageLocker>
 {
 public:
-    static LockedPageManager instance; // instantiated in util.cpp
+    static LockedPageManager& Instance()
+    {
+        std::call_once(LockedPageManager::init_flag, LockedPageManager::CreateInstance);
+        return *LockedPageManager::_instance;
+    }
 private:
-    LockedPageManager():
-        LockedPageManagerBase<MemoryPageLocker>(GetSystemPageSize())
-    {}
+    LockedPageManager();
+
+    static void CreateInstance()
+    {
+        // Using a local static instance guarantees that the object is initialized
+        // when it's first needed and also deinitialized after all objects that use
+        // it are done with it.  I can think of one unlikely scenario where we may
+        // have a static deinitialization order/problem, but the check in
+        // LockedPageManagerBase's destructor helps us detect if that ever happens.
+        static LockedPageManager instance;
+        LockedPageManager::_instance = &instance;
+    }
+
+    static LockedPageManager* _instance;
+    static std::once_flag init_flag;
 };
 
 //
@@ -202,21 +181,21 @@ struct secure_allocator : public std::allocator<T>
     template<typename _Other> struct rebind
     { typedef secure_allocator<_Other> other; };
 
-    T* allocate(std::size_t n, const void *hint = 0)
+    T* allocate(std::size_t n, const void *hint = nullptr)
     {
         T *p;
         p = std::allocator<T>::allocate(n, hint);
-        if (p != NULL)
-            LockedPageManager::instance.LockRange(p, sizeof(T) * n);
+        if (p != nullptr)
+            LockedPageManager::Instance().LockRange(p, sizeof(T) * n);
         return p;
     }
 
     void deallocate(T* p, std::size_t n)
     {
-        if (p != NULL)
+        if (p != nullptr)
         {
             OPENSSL_cleanse(p, sizeof(T) * n);
-            LockedPageManager::instance.UnlockRange(p, sizeof(T) * n);
+            LockedPageManager::Instance().UnlockRange(p, sizeof(T) * n);
         }
         std::allocator<T>::deallocate(p, n);
     }
@@ -248,7 +227,7 @@ struct zero_after_free_allocator : public std::allocator<T>
 
     void deallocate(T* p, std::size_t n)
     {
-        if (p != NULL)
+        if (p != nullptr)
             OPENSSL_cleanse(p, sizeof(T) * n);
         std::allocator<T>::deallocate(p, n);
     }
index 733d9a3..20208e9 100644 (file)
@@ -88,16 +88,16 @@ public:
         // Try to keep the key data out of swap (and be a bit over-careful to keep the IV that we don't even use out of swap)
         // Note that this does nothing about suspend-to-disk (which will put all our key data on disk)
         // Note as well that at no point in this program is any attempt made to prevent stealing of keys by reading the memory of the running process.
-        LockedPageManager::instance.LockRange(&chKey[0], sizeof chKey);
-        LockedPageManager::instance.LockRange(&chIV[0], sizeof chIV);
+        LockedPageManager::Instance().LockRange(&chKey[0], sizeof chKey);
+        LockedPageManager::Instance().LockRange(&chIV[0], sizeof chIV);
     }
 
     ~CCrypter()
     {
         CleanKey();
 
-        LockedPageManager::instance.UnlockRange(&chKey[0], sizeof chKey);
-        LockedPageManager::instance.UnlockRange(&chIV[0], sizeof chIV);
+        LockedPageManager::Instance().UnlockRange(&chKey[0], sizeof chKey);
+        LockedPageManager::Instance().UnlockRange(&chIV[0], sizeof chIV);
     }
 };
 
index ff99c1f..58cee1a 100644 (file)
@@ -79,8 +79,6 @@ void locking_callback(int mode, int i, const char* file, int line)
     }
 }
 
-LockedPageManager LockedPageManager::instance;
-
 // Init
 class CInit
 {