Fix possible race condition with reentrant callback groups in EventsCBGExecutor scheduler - #3234
Open
skyegalaxy wants to merge 2 commits into
Open
Fix possible race condition with reentrant callback groups in EventsCBGExecutor scheduler#3234skyegalaxy wants to merge 2 commits into
skyegalaxy wants to merge 2 commits into
Conversation
added 2 commits
August 22, 2026 19:37
Signed-off-by: Skyler Medeiros <skye@polymathrobotics.com>
Signed-off-by: Skyler Medeiros <skye@polymathrobotics.com>
jmachowinski
approved these changes
Aug 23, 2026
Member
Author
|
Pulls: #3234 |
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.
Description
Since #3178, although the setting of
handle->in_queue = truewas protected underready_callback_groups_mutex, the read is not. This makes the following races possible with more than one worker thread:if
handle->in_queueis loaded stale false while another thread enqueues it and markshandle->in_queue = true, a duplicate handle can be pushed. Removing the callback group or node from a running executor later on can lead to a possible use-after-free if checking for work on the remaining duplicate (dangling) callback handle.In a more rare case, if the check for
handle->in_queueis loaded stale true by the last worker thread to touch it, while another thread setshandle->in_queue = false, a reentrant CBG could have ready work but not be enqueued and stay permanently starved during the lifetime of the executor.Fixed by ensuring that
handle->in_queueis checked underready_callback_groups_mutex.Also adds a check in
remove_callback_groupso that it is only removed fromready_callback_groupsif it was found in the queue. previously if it wasn't ready when being removed,std::findcould returnready_callback_groups.end()and unconditionally erase that fromready_callback_groups, which is undefined behavior.Is this user-facing behavior change?
fixes the possibility of duplicate reentrant groups being pushed to the queue, or a push being skipped indefinitely if the last pending worker thread loads a stale
in_queue = trueDid you use Generative AI?
This came up as a possible race while running a large benchmark sweep, partially instrumented by Claude Opus 5
Additional Information