1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 01:57:45 +00:00

AK: Switch RefCounted to atomic refcounting

This fixes all sorts of race conditions, primarily in the kernel, where till
now it's been possible to obtain either double free or use-after-free by
exploiting refcounting races.
This commit is contained in:
Sergey Bugaev 2020-06-12 16:38:24 +03:00 committed by Andreas Kling
parent 583108004c
commit c80e657dda

View file

@ -27,6 +27,7 @@
#pragma once #pragma once
#include <AK/Assertions.h> #include <AK/Assertions.h>
#include <AK/Atomic.h>
#include <AK/Platform.h> #include <AK/Platform.h>
#include <AK/StdLibExtras.h> #include <AK/StdLibExtras.h>
@ -62,8 +63,8 @@ public:
ALWAYS_INLINE void ref() const ALWAYS_INLINE void ref() const
{ {
ASSERT(m_ref_count); auto old_ref_count = m_ref_count++;
++m_ref_count; ASSERT(old_ref_count > 0);
} }
ALWAYS_INLINE RefCountType ref_count() const ALWAYS_INLINE RefCountType ref_count() const
@ -78,13 +79,14 @@ protected:
ASSERT(m_ref_count == 0); ASSERT(m_ref_count == 0);
} }
ALWAYS_INLINE void deref_base() const ALWAYS_INLINE RefCountType deref_base() const
{ {
ASSERT(m_ref_count); auto old_ref_count = m_ref_count--;
--m_ref_count; ASSERT(old_ref_count > 0);
return old_ref_count - 1;
} }
mutable RefCountType m_ref_count { 1 }; mutable Atomic<RefCountType> m_ref_count { 1 };
}; };
template<typename T> template<typename T>
@ -92,11 +94,11 @@ class RefCounted : public RefCountedBase {
public: public:
void unref() const void unref() const
{ {
deref_base(); auto new_ref_count = deref_base();
if (m_ref_count == 0) { if (new_ref_count == 0) {
call_will_be_destroyed_if_present(static_cast<const T*>(this)); call_will_be_destroyed_if_present(static_cast<const T*>(this));
delete static_cast<const T*>(this); delete static_cast<const T*>(this);
} else if (m_ref_count == 1) { } else if (new_ref_count == 1) {
call_one_ref_left_if_present(static_cast<const T*>(this)); call_one_ref_left_if_present(static_cast<const T*>(this));
} }
} }