From 48eee1709127cb385cafdd105c350b6c1ec0cf3d Mon Sep 17 00:00:00 2001 From: Sergey Abbakumov Date: Mon, 1 Oct 2018 00:57:09 +0700 Subject: [PATCH 1/2] Remove invoking of the non-trivial destructor. Don't expose the risk of accessing objects after the end of their lifetime --- json11.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/json11.cpp b/json11.cpp index 9647846..f2807b8 100644 --- a/json11.cpp +++ b/json11.cpp @@ -236,14 +236,14 @@ struct Statics { }; static const Statics & statics() { - static const Statics s {}; - return s; + static const auto s = new Statics(); + return *s; } static const Json & static_null() { // This has to be separate, not in Statics, because Json() accesses statics().null. - static const Json json_null; - return json_null; + static const auto json_null = new Json(); + return *json_null; } /* * * * * * * * * * * * * * * * * * * * From 92df4071cabae38af271005f38bdaec394603063 Mon Sep 17 00:00:00 2001 From: Sergey Abbakumov Date: Mon, 22 Oct 2018 08:57:48 +0700 Subject: [PATCH 2/2] Use NoDestructor in order to not to leak memory on library loading/unloading --- json11.cpp | 41 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/json11.cpp b/json11.cpp index f2807b8..b0f9341 100644 --- a/json11.cpp +++ b/json11.cpp @@ -25,6 +25,8 @@ #include #include #include +#include +#include namespace json11 { @@ -46,6 +48,41 @@ struct NullStruct { bool operator<(NullStruct) const { return false; } }; +/* NoDestructor + * + * Wrapper that makes it easy to create an object of type T with static storage duration that: + * - is only constructed on first access + * - never invokes the destructor + */ +template +class NoDestructor { +public: + template + explicit NoDestructor(Args&&... args) { + new (storage_) T(std::forward(args)...); + } + + explicit NoDestructor(const T& x) { new (storage_) T(x); } + explicit NoDestructor(T&& x) { new (storage_) T(std::move(x)); } + + NoDestructor(const NoDestructor&) = delete; + NoDestructor& operator=(const NoDestructor&) = delete; + + ~NoDestructor() = default; + + const T& operator*() const { return *get(); } + T& operator*() { return *get(); } + + const T* operator->() const { return get(); } + T* operator->() { return get(); } + + const T* get() const { return reinterpret_cast(storage_); } + T* get() { return reinterpret_cast(storage_); } + +private: + alignas(T) char storage_[sizeof(T)]; +}; + /* * * * * * * * * * * * * * * * * * * * * Serialization */ @@ -236,13 +273,13 @@ struct Statics { }; static const Statics & statics() { - static const auto s = new Statics(); + static const NoDestructor s; return *s; } static const Json & static_null() { // This has to be separate, not in Statics, because Json() accesses statics().null. - static const auto json_null = new Json(); + static const NoDestructor json_null; return *json_null; }