LibCore: Check for null ThreadData in unregister_notifier

and unregister_timer in EventLoopManagerWindows

Destructors for thread local objects are called before destructors of
global not thread local objects.

This is a partial stack of the problem, thread_data is already
destroyed at this point:

>WebContent.exe!Core::ThreadData::the
 WebContent.exe!Core::EventLoopManagerWindows::unregister_notifier
 WebContent.exe!Core::EventLoop::unregister_notifier
 WebContent.exe!Core::Notifier::set_enabled
 WebContent.exe!Core::LocalSocket::~LocalSocket
 WebContent.exe!Requests::RequestClient::~RequestClient
 WebContent.exe!Web::`dynamic atexit destructor for 's_resource_loader'
This commit is contained in:
stasoid 2025-01-08 11:41:50 +05:00 committed by Andrew Kaster
parent b53694b4c0
commit 33457f389d
Notes: github-actions[bot] 2025-04-11 01:03:27 +00:00

View file

@ -55,10 +55,12 @@ struct EventLoopTimer {
};
struct ThreadData {
static ThreadData& the()
static ThreadData* the()
{
thread_local OwnPtr<ThreadData> thread_data = make<ThreadData>();
return *thread_data;
if (thread_data)
return &*thread_data;
return nullptr;
}
ThreadData()
@ -76,7 +78,7 @@ struct ThreadData {
};
EventLoopImplementationWindows::EventLoopImplementationWindows()
: m_wake_event(ThreadData::the().wake_event.handle)
: m_wake_event(ThreadData::the()->wake_event.handle)
{
}
@ -92,9 +94,9 @@ int EventLoopImplementationWindows::exec()
size_t EventLoopImplementationWindows::pump(PumpMode)
{
auto& thread_data = ThreadData::the();
auto& notifiers = thread_data.notifiers;
auto& timers = thread_data.timers;
auto thread_data = ThreadData::the();
auto& notifiers = thread_data->notifiers;
auto& timers = thread_data->timers;
size_t event_count = 1 + notifiers.size() + timers.size();
// If 64 events limit proves to be insufficient RegisterWaitForSingleObject or other methods
@ -103,7 +105,7 @@ size_t EventLoopImplementationWindows::pump(PumpMode)
VERIFY(event_count <= MAXIMUM_WAIT_OBJECTS);
Vector<HANDLE, MAXIMUM_WAIT_OBJECTS> event_handles;
event_handles.append(thread_data.wake_event.handle);
event_handles.append(thread_data->wake_event.handle);
for (auto& entry : notifiers)
event_handles.append(entry.key.handle);
@ -167,7 +169,7 @@ void EventLoopManagerWindows::register_notifier(Notifier& notifier)
int rc = WSAEventSelect(notifier.fd(), event, notifier_type_to_network_event(notifier.type()));
VERIFY(!rc);
auto& notifiers = ThreadData::the().notifiers;
auto& notifiers = ThreadData::the()->notifiers;
VERIFY(!notifiers.get(event).has_value());
notifiers.set(Handle(event), &notifier);
}
@ -175,7 +177,8 @@ void EventLoopManagerWindows::register_notifier(Notifier& notifier)
void EventLoopManagerWindows::unregister_notifier(Notifier& notifier)
{
// remove_first_matching would be clearer, but currently there is no such method in HashMap
ThreadData::the().notifiers.remove_all_matching([&](auto&, auto value) { return value == &notifier; });
if (ThreadData::the())
ThreadData::the()->notifiers.remove_all_matching([&](auto&, auto value) { return value == &notifier; });
}
intptr_t EventLoopManagerWindows::register_timer(EventReceiver& object, int milliseconds, bool should_reload, TimerShouldFireWhenNotVisible fire_when_not_visible)
@ -190,15 +193,16 @@ intptr_t EventLoopManagerWindows::register_timer(EventReceiver& object, int mill
BOOL rc = SetWaitableTimer(timer, &first_time, should_reload ? milliseconds : 0, NULL, NULL, FALSE);
VERIFY(rc);
auto& timers = ThreadData::the().timers;
auto& timers = ThreadData::the()->timers;
VERIFY(!timers.get(timer).has_value());
timers.set(Handle(timer), { object, fire_when_not_visible });
return (intptr_t)timer;
return reinterpret_cast<intptr_t>(timer);
}
void EventLoopManagerWindows::unregister_timer(intptr_t timer_id)
{
ThreadData::the().timers.remove((HANDLE)timer_id);
if (ThreadData::the())
ThreadData::the()->timers.remove(reinterpret_cast<HANDLE>(timer_id));
}
int EventLoopManagerWindows::register_signal([[maybe_unused]] int signal_number, [[maybe_unused]] Function<void(int)> handler)