summaryrefslogtreecommitdiff
path: root/integer.cpp
diff options
context:
space:
mode:
authorJeffrey Walton <noloader@gmail.com>2017-03-27 06:06:12 -0400
committerJeffrey Walton <noloader@gmail.com>2017-03-27 06:06:12 -0400
commitc305e8812772582edeb6e373b6e34feb59f3799f (patch)
tree84e708e728b0c6a9e3fc8b0594dd896a76d08494 /integer.cpp
parent0e55f5ac7d98f3c852ace7b4622f40cfa60b629f (diff)
downloadcryptopp-git-c305e8812772582edeb6e373b6e34feb59f3799f.tar.gz
Fix runtime crash when CRYPTOPP_INIT_PRIORITY=0
Couple use of initialization priorities to no NO_OS_DEPENDENCE Add comments explaining what integer does, how it does it, and why we want to inprove on the Singleton pattern as a resource manager. Update documentation.
Diffstat (limited to 'integer.cpp')
-rw-r--r--integer.cpp79
1 files changed, 70 insertions, 9 deletions
diff --git a/integer.cpp b/integer.cpp
index 8df0b567..317ad89f 100644
--- a/integer.cpp
+++ b/integer.cpp
@@ -1,6 +1,37 @@
// integer.cpp - originally written and placed in the public domain by Wei Dai
// contains public domain code contributed by Alister Lee and Leonard Janke
+// Notes by JW: The Integer class needs to do two things. First, it needs to set function
+// pointers on some platforms, like X86 and X64. The function pointers select a fast multiply
+// and addition based on the cpu. Second, it wants to create Integer::Zero(), Integer::One()
+// and Integer::Two(). The function pointers are initialized in the class InitializeInteger.
+// Wei's original code was much simpler. It uses the Singleton pattern, but it always produced
+// memory findings. The Singleton generates memory findings because it used for a Create on
+// First Use pattern. Resource destruction effectivley requires running resource acquisition
+// with dependencies in reverse. For resources provided through the Singletons, there is no way
+// to express the dependency order to safely destroy resources.
+// The difference in the changes below is we use platform and language specific remediations
+// if they are available. If not available, then we fall back to Wei's original code. If
+// NO_OS_DEPENDENCE is defined, then the library uses Wei's original code.
+// Under all versions of C++ on Linux and Microsoft platforms, we can use GCC's init_priority
+// or MSVC's init_seg(lib) to initialize the function pointers and create the Integers 0, 1 and 2
+// after CRT startup. This avoids the Singletons and clears over half the reports of memory
+// leaks. However, it does not apply to Apple or Sun platforms.
+// C++11 allows us to use call_once to set the function pointers, and Integer does so when
+// init_priority and init_seg(lib) are not available. The class also uses the Singleton pattern
+// to ensure integers 0, 1 and 2 are available. The Singleton will produce memory findings, but
+// we don't have anything else to use in this case.
+// C++03 on platforms like Apple and Sun, we use a boolean flag to track when the function pointers
+// have been set based on the cpu. Its just a Nifty Counter in disguise, and its similar to using
+// the g_pAssignToInteger to track initialization. It has concurrency issues, but a race is not a
+// problem. It does not matter if two threads both set the same pointers. The Singleton pattern
+// is also used to ensure integers 0, 1 and 2 are available. The Singleton will produce memory
+// findings, but we don't have anything else to use in this case.
+// While not readily apparent, Integer does not need to inherit from InitializeInteger when
+// init_priority and init_seg(lib) are available. They just create an InitializePointers object
+// at the right time after CRT initialization. The additional class avoids the small runtime
+// overhead associated with checking the flags, and hides the detail from the interface.
+
#include "pch.h"
#include "config.h"
@@ -28,6 +59,7 @@
#include "smartptr.h"
#include "algparam.h"
#include "filters.h"
+#include "stdcpp.h"
#include "asn.h"
#include "oids.h"
#include "words.h"
@@ -73,11 +105,40 @@
NAMESPACE_BEGIN(CryptoPP)
static void SetFunctionPointers();
+#if defined(HAVE_GCC_INIT_PRIORITY) || defined(HAVE_MSC_INIT_PRIORITY)
+// Add InitializePointers to perform the work of setting pointers once.
+struct InitializePointers
+{
+ InitializePointers()
+ {
+ SetFunctionPointers();
+ }
+};
+// Leave InitializeInteger empty so no work is done.
InitializeInteger::InitializeInteger()
{
- SetFunctionPointers();
}
-
+#elif defined(CRYPTOPP_CXX11_SYNCHRONIZATION) && defined(CRYPTOPP_CXX11_DYNAMIC_INIT)
+std::once_flag s_flag;
+InitializeInteger::InitializeInteger()
+{
+ std::call_once(s_flag, []() {
+ SetFunctionPointers();
+ });
+}
+#else
+static bool s_flag;
+InitializeInteger::InitializeInteger()
+{
+ MEMORY_BARRIER();
+ if (s_flag == false)
+ {
+ SetFunctionPointers();
+ s_flag = true;
+ MEMORY_BARRIER();
+ }
+}
+#endif
template <long i>
struct NewInteger
{
@@ -89,15 +150,15 @@ struct NewInteger
NAMESPACE_END
ANONYMOUS_NAMESPACE_BEGIN
-#if HAVE_GCC_INIT_PRIORITY
-const CryptoPP::InitializeInteger s_init __attribute__ ((init_priority (CRYPTOPP_INIT_PRIORITY + 30))) = CryptoPP::InitializeInteger();
+#if defined(HAVE_GCC_INIT_PRIORITY)
+const CryptoPP::InitializePointers s_init __attribute__ ((init_priority (CRYPTOPP_INIT_PRIORITY + 30))) = CryptoPP::InitializePointers();
const CryptoPP::Integer s_zero __attribute__ ((init_priority (CRYPTOPP_INIT_PRIORITY + 31))) = CryptoPP::Integer(0L);
const CryptoPP::Integer s_one __attribute__ ((init_priority (CRYPTOPP_INIT_PRIORITY + 32))) = CryptoPP::Integer(1L);
const CryptoPP::Integer s_two __attribute__ ((init_priority (CRYPTOPP_INIT_PRIORITY + 33))) = CryptoPP::Integer(2L);
-#elif HAVE_MSC_INIT_PRIORITY
+#elif defined(HAVE_MSC_INIT_PRIORITY)
#pragma warning(disable: 4075)
#pragma init_seg(".CRT$XCU-030")
-const CryptoPP::InitializeInteger s_init;
+const CryptoPP::InitializePointers s_init;
const CryptoPP::Integer s_zero(0L);
const CryptoPP::Integer s_one(1L);
const CryptoPP::Integer s_two(2L);
@@ -3025,7 +3086,7 @@ Integer Integer::Power2(size_t e)
const Integer &Integer::Zero()
{
-#if HAVE_GCC_INIT_PRIORITY || HAVE_MSC_INIT_PRIORITY
+#if defined(HAVE_GCC_INIT_PRIORITY) || defined(HAVE_MSC_INIT_PRIORITY)
return s_zero;
#else
return Singleton<Integer, NewInteger<0L> >().Ref();
@@ -3034,7 +3095,7 @@ const Integer &Integer::Zero()
const Integer &Integer::One()
{
-#if HAVE_GCC_INIT_PRIORITY || HAVE_MSC_INIT_PRIORITY
+#if defined(HAVE_GCC_INIT_PRIORITY) || defined(HAVE_MSC_INIT_PRIORITY)
return s_one;
#else
return Singleton<Integer, NewInteger<1L> >().Ref();
@@ -3043,7 +3104,7 @@ const Integer &Integer::One()
const Integer &Integer::Two()
{
-#if HAVE_GCC_INIT_PRIORITY || HAVE_MSC_INIT_PRIORITY
+#if defined(HAVE_GCC_INIT_PRIORITY) || defined(HAVE_MSC_INIT_PRIORITY)
return s_two;
#else
return Singleton<Integer, NewInteger<2L> >().Ref();