Repository navigation
fix null _p access in the TestNode async_delay timer handler - #1243
Merged
facontidavide merged 1 commit intoOct 24, 2026
Merged
Conversation
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.
TestNode::onStart arms a TimerQueue handler for
async_delay, and that handler reaches its state through_p->completed. The TimerQueue itself lives insideTestNode::PImpl, and~TimerQueue()runs every pending handler withaborted=trueon its worker thread while it joins, so the handler executes in the middle of deleting the PImpl. libc++'sunique_ptrclears its pointer before calling the deleter, so_pis null at that point and the store crashes the process (UBSan reports a member access within null pointer of typeTestNode::PImpl, ASan a SEGV at test_node.cpp:144); with libstdc++ it instead writes intocompletedafter it was destroyed, since it was declared aftertimer. I ran into it just by letting a tree go out of scope after one tick while a substituted TestNode withasync_delaywas still RUNNING:~Treehalts first, butcancelAll()only schedules the aborted handler, so the destruction usually wins the race. The handler now captures the PImpl pointer instead of reading_p, andtimeris declared last in PImpl so it is joined whilecompletedis still alive, the same ordering #1180 applied to Sleep, Delay and Timeout. PImpl is private, so there is no API or ABI change, and the newSubstitution.DestroyTestNodeWithPendingAsyncDelayaborts under the ASan/UBSan build on master and passes with the fix.