1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 06:17:35 +00:00

AK: Fix leak in WeakPtr(WeakPtr&&) and WeakPtr::operator=(WeakPtr&&)

We were forgetting to adopt the WeakLink, causing a reference leak.
This ended up costing us one allocation per exec(), with this stack:

    kmalloc_impl()
    Inode::set_vmo()
    InodeVMObject::create_with_inode()
    Process::do_exec()
    Process::exec()
    Process::sys$execve()

This was a pain to track down, in the end I caught it by dumping out
every live kmalloc pointer between runs and diffing the sets. Then it
was just a matter of matching the pointer to a call stack and looking
at what went wrong. :^)
This commit is contained in:
Andreas Kling 2019-11-15 15:50:13 +01:00
parent 7ef9c703d2
commit e89cdd504c

View file

@ -18,14 +18,14 @@ public:
template<typename U> template<typename U>
WeakPtr(WeakPtr<U>&& other) WeakPtr(WeakPtr<U>&& other)
: m_link(reinterpret_cast<WeakLink<T>*>(other.leak_link())) : m_link(reinterpret_cast<WeakLink<T>*>(other.take_link().ptr()))
{ {
} }
template<typename U> template<typename U>
WeakPtr& operator=(WeakPtr<U>&& other) WeakPtr& operator=(WeakPtr<U>&& other)
{ {
m_link = reinterpret_cast<WeakLink<T>*>(other.leak_link()); m_link = reinterpret_cast<WeakLink<T>*>(other.take_link().ptr());
return *this; return *this;
} }
@ -46,7 +46,7 @@ public:
bool is_null() const { return !m_link || !m_link->ptr(); } bool is_null() const { return !m_link || !m_link->ptr(); }
void clear() { m_link = nullptr; } void clear() { m_link = nullptr; }
WeakLink<T>* leak_link() { return m_link.leak_ref(); } RefPtr<WeakLink<T>> take_link() { return move(m_link); }
bool operator==(const OwnPtr<T>& other) const { return ptr() == other.ptr(); } bool operator==(const OwnPtr<T>& other) const { return ptr() == other.ptr(); }