Skip to content

Fix possible race condition with reentrant callback groups in EventsCBGExecutor scheduler (backport #3234) - #3237

Merged
jmachowinski merged 1 commit into
kiltedfrom
mergify/bp/kilted/pr-3234
Aug 24, 2026
Merged

Fix possible race condition with reentrant callback groups in EventsCBGExecutor scheduler (backport #3234)#3237
jmachowinski merged 1 commit into
kiltedfrom
mergify/bp/kilted/pr-3234

Conversation

@mergify

@mergify mergify Bot commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Description

Since #3178, although the setting of handle->in_queue = true was protected under ready_callback_groups_mutex, the read is not. This makes the following races possible with more than one worker thread:

if handle->in_queue is loaded stale false while another thread enqueues it and marks handle->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_queue is loaded stale true by the last worker thread to touch it, while another thread sets handle->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_queue is checked under ready_callback_groups_mutex.

Also adds a check in remove_callback_group so that it is only removed from ready_callback_groups if it was found in the queue. previously if it wasn't ready when being removed, std::find could return ready_callback_groups.end() and unconditionally erase that from ready_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 = true

Did 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


This is an automatic backport of pull request #3234 done by [Mergify](https://mergify.com).

…BGExecutor scheduler (#3234)

* put in_queue under ready_callback_groups_mutex

Signed-off-by: Skyler Medeiros <skye@polymathrobotics.com>

* only remove from ready_callback_groups if in the queue

Signed-off-by: Skyler Medeiros <skye@polymathrobotics.com>

---------

Signed-off-by: Skyler Medeiros <skye@polymathrobotics.com>
Co-authored-by: Skyler Medeiros <skye@polymathrobotics.com>
(cherry picked from commit 4528e3c)
@skyegalaxy

skyegalaxy commented Aug 24, 2026

Copy link
Copy Markdown
Member

Pulls: #3237
Gist: https://gist.githubusercontent.com/skyegalaxy/81742caa1e7b86621f4ab0fb59e523bc/raw/ca14e451cc9dff23250986e01222fec16092d566/ros2.repos
BUILD args: --packages-above-and-dependencies rclcpp
TEST args: --packages-above rclcpp
ROS Distro: kilted
Job: ci_launcher
ci_launcher ran: https://ci.ros2.org/job/ci_launcher/20176

  • Linux Build Status
  • Linux-aarch64 Build Status
  • Linux-rhel Build Status
  • Windows Build Status

@jmachowinski
jmachowinski merged commit 504c67f into kilted Aug 24, 2026
2 checks passed
@ahcorde
ahcorde deleted the mergify/bp/kilted/pr-3234 branch August 24, 2026 15:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants