core: fix use-after-free segfault in async resource widget callbacks#961
Merged
PointerDilemma merged 1 commit intohyprwm:mainfrom Feb 20, 2026
Merged
Conversation
Properly lock AWP<IWidget> weak pointers before calling onAssetUpdate() to prevent use-after-free when widgets are destroyed during shutdown or output removal. Guard timer callback against null g_asyncResourceManager. Fix destruction order to join threads before resetting globals.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes a segfault (SIGSEGV at address
0xc) caused by use-after-free whenAWP<IWidget>weak pointers are dereferenced without proper locking inAsyncResourceManager. This crash occurs frequently during lock/unlock cycles, especially on suspend/resume where outputs are removed while async resources are still in-flight.Relates to #942.
Root Cause
onResourceFinished()andrequest()checkif (widget)before callingwidget->onAssetUpdate(), butAWP::operator bool()only checks if the raw pointer is non-null — it does not verify the underlying object is still alive. When widgets are destroyed during shutdown or output removal, the weak pointer still appears valid but the object is freed, causing a vtable dispatch on a destroyed object (crash at offset0xc).Additionally, the exit path destroyed global objects (
g_asyncResourceManager,g_pRenderer) while timer and poll threads were still running, allowing callbacks to reference freed state.Changes
widget.lock()instead ofif (widget)inonResourceFinished()andrequest(). Thelock()method correctly checksdataNonNull(),destroying(), andlockable().renderAllOutputs()whenwidget.lock()succeeds.g_asyncResourceManagerduring shutdown.g_pHyprlockduring destruction of the async resource manager.Crash Backtrace (before fix)
segfault at c= null pointer + small offset, consistent with vtable dispatch on a destroyed object.Testing