From 0f288aecdd158cb13e16a5f76537b44df32a7d8e Mon Sep 17 00:00:00 2001 From: Christopher Dunn Date: Sun, 26 Jun 2016 18:47:43 -0500 Subject: [PATCH] Use a Myers Singleton for null Avoid some static initialization problems. From @marklakata See #488 --- include/json/value.h | 2 ++ src/lib_json/json_value.cpp | 44 +++++++++++++++++++++++-------------- 2 files changed, 30 insertions(+), 16 deletions(-) diff --git a/include/json/value.h b/include/json/value.h index 4c29382..fb88c18 100644 --- a/include/json/value.h +++ b/include/json/value.h @@ -190,6 +190,8 @@ public: static const Value& null; ///< We regret this reference to a global instance; prefer the simpler Value(). static const Value& nullRef; ///< just a kludge for binary-compatibility; same as null + static Value const& nullSingleton(); ///< Prefer this to null or nullRef. + /// Minimum signed integer value that can be stored in a Json::Value. static const LargestInt minLargestInt; /// Maximum signed integer value that can be stored in a Json::Value. diff --git a/src/lib_json/json_value.cpp b/src/lib_json/json_value.cpp index e195594..1d86883 100644 --- a/src/lib_json/json_value.cpp +++ b/src/lib_json/json_value.cpp @@ -31,10 +31,22 @@ namespace Json { #else #define ALIGNAS(byte_alignment) #endif -static const unsigned char ALIGNAS(8) kNull[sizeof(Value)] = { 0 }; -const unsigned char& kNullRef = kNull[0]; -const Value& Value::null = reinterpret_cast(kNullRef); -const Value& Value::nullRef = null; +//static const unsigned char ALIGNAS(8) kNull[sizeof(Value)] = { 0 }; +//const unsigned char& kNullRef = kNull[0]; +//const Value& Value::null = reinterpret_cast(kNullRef); +//const Value& Value::nullRef = null; + +// static +Value const& Value::nullSingleton() +{ + static Value const* nullStatic = new Value; + return *nullStatic; +} + +// for backwards compatibility, we'll leave these global references around, but DO NOT +// use them in JSONCPP library code any more! +Value const& Value::null = Value::nullSingleton(); +Value const& Value::nullRef = Value::nullSingleton(); const Int Value::minInt = Int(~(UInt(-1) / 2)); const Int Value::maxInt = Int(UInt(-1) / 2); @@ -972,7 +984,7 @@ Value& Value::operator[](ArrayIndex index) { if (it != value_.map_->end() && (*it).first == key) return (*it).second; - ObjectValues::value_type defaultValue(key, nullRef); + ObjectValues::value_type defaultValue(key, nullSingleton()); it = value_.map_->insert(it, defaultValue); return (*it).second; } @@ -989,11 +1001,11 @@ const Value& Value::operator[](ArrayIndex index) const { type_ == nullValue || type_ == arrayValue, "in Json::Value::operator[](ArrayIndex)const: requires arrayValue"); if (type_ == nullValue) - return nullRef; + return nullSingleton(); CZString key(index); ObjectValues::const_iterator it = value_.map_->find(key); if (it == value_.map_->end()) - return nullRef; + return nullSingleton(); return (*it).second; } @@ -1027,7 +1039,7 @@ Value& Value::resolveReference(const char* key) { if (it != value_.map_->end() && (*it).first == actualKey) return (*it).second; - ObjectValues::value_type defaultValue(actualKey, nullRef); + ObjectValues::value_type defaultValue(actualKey, nullSingleton()); it = value_.map_->insert(it, defaultValue); Value& value = (*it).second; return value; @@ -1047,7 +1059,7 @@ Value& Value::resolveReference(char const* key, char const* cend) if (it != value_.map_->end() && (*it).first == actualKey) return (*it).second; - ObjectValues::value_type defaultValue(actualKey, nullRef); + ObjectValues::value_type defaultValue(actualKey, nullSingleton()); it = value_.map_->insert(it, defaultValue); Value& value = (*it).second; return value; @@ -1055,7 +1067,7 @@ Value& Value::resolveReference(char const* key, char const* cend) Value Value::get(ArrayIndex index, const Value& defaultValue) const { const Value* value = &((*this)[index]); - return value == &nullRef ? defaultValue : *value; + return value == &nullSingleton() ? defaultValue : *value; } bool Value::isValidIndex(ArrayIndex index) const { return index < size(); } @@ -1074,13 +1086,13 @@ Value const* Value::find(char const* key, char const* cend) const const Value& Value::operator[](const char* key) const { Value const* found = find(key, key + strlen(key)); - if (!found) return nullRef; + if (!found) return nullSingleton(); return *found; } Value const& Value::operator[](JSONCPP_STRING const& key) const { Value const* found = find(key.data(), key.data() + key.length()); - if (!found) return nullRef; + if (!found) return nullSingleton(); return *found; } @@ -1103,7 +1115,7 @@ Value& Value::operator[](const CppTL::ConstString& key) { Value const& Value::operator[](CppTL::ConstString const& key) const { Value const* found = find(key.c_str(), key.end_c_str()); - if (!found) return nullRef; + if (!found) return nullSingleton(); return *found; } #endif @@ -1151,7 +1163,7 @@ Value Value::removeMember(const char* key) JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == objectValue, "in Json::Value::removeMember(): requires objectValue"); if (type_ == nullValue) - return nullRef; + return nullSingleton(); Value removed; // null removeMember(key, key + strlen(key), &removed); @@ -1538,7 +1550,7 @@ const Value& Path::resolve(const Value& root) const { // Error: unable to resolve path (object value expected at position...) } node = &((*node)[arg.key_]); - if (node == &Value::nullRef) { + if (node == &Value::nullSingleton()) { // Error: unable to resolve path (object has no member named '' at // position...) } @@ -1559,7 +1571,7 @@ Value Path::resolve(const Value& root, const Value& defaultValue) const { if (!node->isObject()) return defaultValue; node = &((*node)[arg.key_]); - if (node == &Value::nullRef) + if (node == &Value::nullSingleton()) return defaultValue; } }