Open chazzmcdaniels opened 2 years ago
Yep, the problem is the Singleton<T>
implementation in
https://github.com/weidai11/cryptopp/blob/master/misc.h#L332-L352
Does something like:
static std::atomic<T*> s_pObject;
T *newObject = m_objectFactory(); // where m_objectFactory is `new T`
s_pObject.store(newObject);
But the heap allocated object stored in s_pObject
is never deleted on exit. This can be fixed by implementing an atomic_unique_ptr
like the following
template<typename T>
struct atomic_unique_ptr {
using pointer = T *;
std::atomic<pointer> ptr;
constexpr atomic_unique_ptr() noexcept : ptr() {}
explicit atomic_unique_ptr(pointer p) noexcept : ptr(p) {}
atomic_unique_ptr(atomic_unique_ptr&& p) noexcept : ptr(p.release()) {}
atomic_unique_ptr& operator=(atomic_unique_ptr&& p) noexcept { reset(p.release()); return *this; }
void reset(pointer p = pointer()) { auto old = ptr.exchange(p); if (old) delete old; }
operator pointer() const { return ptr; }
pointer operator->() const { return ptr; }
pointer get() const { return ptr; }
explicit operator bool() const { return ptr != pointer(); }
pointer release() { return ptr.exchange(pointer()); }
~atomic_unique_ptr() { reset(); }
};
Then replacing the static std::atomic<T*> s_pObject
with an atomic_unique_ptr<T>
as a drop-in replacement, fixing the memory leaks.
On Sun, Oct 15, 2023 at 4:34 AM Dale Weiler @.***> wrote:
Yep, the solution would be to just implement something like atomic_unique_ptr so that the object returned by m_objectFactory would also deleted correctly.
template
struct atomic_unique_ptr { using pointer = T ; std::atomic ptr; constexpr atomic_unique_ptr() noexcept : ptr() {} explicit atomic_unique_ptr(pointer p) noexcept : ptr(p) {} atomic_unique_ptr(atomic_unique_ptr&& p) noexcept : ptr(p.release()) {} atomic_unique_ptr& operator=(atomic_unique_ptr&& p) noexcept { reset(p.release()); return this; } void reset(pointer p = pointer()) { auto old = ptr.exchange(p); if (old) delete old; } operator pointer() const { return ptr; } pointer operator->() const { return ptr; } pointer get() const { return ptr; } explicit operator bool() const { return ptr != pointer(); } pointer release() { return ptr.exchange(pointer()); } ~atomic_unique_ptr() { reset(); } };This more or less works as a drop-in replacement and fixes the memory leaks.
Yeah, the problem is (or has always been) C++03. We still support it. I know there are folks still using Crypto++ on antique platforms, like Windows XP and old versions of GCC like 4.4.
To abstract away the differences between auto_ptr (C++03) and unique_ptr
(C++11), the library provided member_ptr
For the regularly used stuff, like Integer class, we cutover to a pattern that avoids the leak (some hand waving):
const Integer& Integer::Two() const {
static const Integer two(2);
return two;
// SIngleton gyrations
}
If P1363_MGF1 is causing an accumulation of leaks for you, then we can look at cutting it over to the new pattern.
Jeff
Message ID: @.***>
The new in a Singleton has no complementary delete which causes still reachable bytes in memcheck. (misc.h line 258 and 346)
Code snippet to reproduce (FixedMaxPlaintextLength is the trigger here):
Environment: Ubuntu 20.04, Crypto++ 8.7.0, gcc 11.1.0, Valgrind 3.15.0 Command line:
valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all ..........
Expected output: No leaks at all Current output: