Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Don't add new ref to the System instance which is being destroyed (fix aseprite/aseprite#4811) #115

Merged
merged 1 commit into from
Dec 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions os/common/system.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,21 +25,31 @@
#include "clip/clip.h"
#endif

#include "base/debug.h"

namespace os {

// Weak reference to the unique system instance. This is destroyed by
// the user (with the main SystemRef to the system).
System* g_instance = nullptr;

// Flag to know if the intance is already being destroyed, so we
// cannot add a ref to it, i.e. calling System::instance() is illegal
// if this flag is true.
static bool g_is_being_destroyed = false;

SystemRef System::instance()
{
ASSERT(!g_is_being_destroyed);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: no header providing "ASSERT" is directly included [misc-include-cleaner]

os/common/system.cpp:7:

- #ifdef HAVE_CONFIG_H
+ #include "base/debug.h"
+ #ifdef HAVE_CONFIG_H

if (g_instance)
return AddRef(g_instance);
return nullptr;
}

SystemRef System::make()
{
ASSERT(!g_instance);

SystemRef ref;
#if LAF_SKIA
ref = System::makeSkia();
Expand Down Expand Up @@ -72,7 +82,7 @@ CommonSystem::~CommonSystem()
{
// destroyInstance() can be called multiple times by derived
// classes.
if (instance() == this)
if (g_instance == this)
destroyInstance();
}

Expand Down Expand Up @@ -208,8 +218,12 @@ void CommonSystem::destroyInstance()
{
// destroyInstance() can be called multiple times by derived
// classes.
if (g_instance != this)
if (g_instance != this) {
ASSERT(g_is_being_destroyed);
return;
}

g_is_being_destroyed = true;

// We have to reset the list of all events to clear all possible
// living WindowRef (so all window destructors are called at this
Expand Down
14 changes: 11 additions & 3 deletions os/win/window.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@

namespace os {

// Extern raw reference to current system instance.
extern System* g_instance;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: no header providing "os::System" is directly included [misc-include-cleaner]

os/win/window.cpp:7:

- #ifdef HAVE_CONFIG_H
+ #include "os/system.h"
+ #ifdef HAVE_CONFIG_H


// Converts an os::Hit to a Win32 hit test value
static int hit2hittest[] = {
HTNOWHERE, // os::Hit::None
Expand Down Expand Up @@ -135,7 +138,7 @@ static BOOL CALLBACK log_monitor_info(HMONITOR monitor,

std::wstring get_wnd_class_name()
{
if (auto sys = instance()) {
if (auto sys = os::System::instance()) {
if (!sys->appName().empty())
return base::from_utf8(sys->appName());
}
Expand Down Expand Up @@ -322,12 +325,17 @@ WindowWin::WindowWin(const WindowSpec& spec)

WindowWin::~WindowWin()
{
auto sys = system();
// We cannot use os::System::instance() here because that would add
// a new reference to a possible dying System pointer, e.g. when we
// come from ~System because the last Ref::unref() was called and
// this window is being destroyed because its last reference was in
// a os::Event of the os::EventQueue.
SystemWin* sys = (SystemWin*)g_instance;

// If this assert fails it's highly probable that an os::WindowRef
// was kept alive in some kind of memory leak (or just inside an
// os::Event in the os::EventQueue). Also this can happen when
// declaring a os::WindowRef before calling os::make_system(),
// declaring a os::WindowRef before calling os::System::system(),
// because of deletion order when destructors got called.
ASSERT(sys);

Expand Down
Loading