ladybird/AK/WeakPtr.h
Andreas Kling e89cdd504c 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. :^)
2019-11-15 16:07:39 +01:00

79 lines
1.7 KiB
C++

#pragma once
#include <AK/LogStream.h>
#include <AK/Weakable.h>
namespace AK {
template<typename T>
class OwnPtr;
template<typename T>
class WeakPtr {
friend class Weakable<T>;
public:
WeakPtr() {}
WeakPtr(std::nullptr_t) {}
template<typename U>
WeakPtr(WeakPtr<U>&& other)
: m_link(reinterpret_cast<WeakLink<T>*>(other.take_link().ptr()))
{
}
template<typename U>
WeakPtr& operator=(WeakPtr<U>&& other)
{
m_link = reinterpret_cast<WeakLink<T>*>(other.take_link().ptr());
return *this;
}
operator bool() const { return ptr(); }
T* ptr() { return m_link ? m_link->ptr() : nullptr; }
const T* ptr() const { return m_link ? m_link->ptr() : nullptr; }
T* operator->() { return ptr(); }
const T* operator->() const { return ptr(); }
T& operator*() { return *ptr(); }
const T& operator*() const { return *ptr(); }
operator const T*() const { return ptr(); }
operator T*() { return ptr(); }
bool is_null() const { return !m_link || !m_link->ptr(); }
void clear() { m_link = nullptr; }
RefPtr<WeakLink<T>> take_link() { return move(m_link); }
bool operator==(const OwnPtr<T>& other) const { return ptr() == other.ptr(); }
private:
WeakPtr(RefPtr<WeakLink<T>> link)
: m_link(move(link))
{
}
RefPtr<WeakLink<T>> m_link;
};
template<typename T>
inline WeakPtr<T> Weakable<T>::make_weak_ptr()
{
if (!m_link)
m_link = adopt(*new WeakLink<T>(static_cast<T&>(*this)));
return WeakPtr<T>(m_link);
}
template<typename T>
inline const LogStream& operator<<(const LogStream& stream, const WeakPtr<T>& value)
{
return stream << value.ptr();
}
}
using AK::WeakPtr;