Skip to content

Bounds-check EventHandlerBase::is_ready() to fix out-of-bounds read (#2376) - #3170

Open
PavelGuzenfeld wants to merge 1 commit into
ros2:rollingfrom
PavelGuzenfeld:fix/issue-2376-event-handler-is-ready-bounds
Open

Bounds-check EventHandlerBase::is_ready() to fix out-of-bounds read (#2376)#3170
PavelGuzenfeld wants to merge 1 commit into
ros2:rollingfrom
PavelGuzenfeld:fix/issue-2376-event-handler-is-ready-bounds

Conversation

@PavelGuzenfeld

@PavelGuzenfeld PavelGuzenfeld commented Jun 6, 2026

Copy link
Copy Markdown

EventHandlerBase::is_ready() indexes wait_set.events[wait_set_event_index_], but that index is only assigned by add_to_wait_set(). If is_ready() runs before that the member is uninitialized; if it runs against a different wait set the index belongs to that other one. Either way the access reads out of bounds and can segfault (observed with ASan during a lifecycle configure).

This initializes wait_set_event_index_ to an always-out-of-range sentinel and makes is_ready() return false when the index is not within the wait set's events, instead of dereferencing it.

Adds two regression tests: one calling is_ready() on a handler that was never added to a wait set, and one where the index was assigned by a different wait set and equals size_of_events.

Builds on @aosmw's work in #2376; per @clalancette's review there, initializing the index alone is not sufficient (it could still point at another slot), so the bounds check in is_ready() is the actual guard.


Some of this change was produced with Claude Opus 4.8 (Anthropic).

@PavelGuzenfeld
PavelGuzenfeld force-pushed the fix/issue-2376-event-handler-is-ready-bounds branch from 7aa7462 to 048bc4d Compare June 6, 2026 22:24
@mergify

mergify Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Tick the box to add this pull request to the merge queue (same as @mergifyio queue).

  • Queue this pull request

@sylvesterkaczmarek sylvesterkaczmarek left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If add_to_wait_set() and is_ready() can genuinely race as described, the bounds check fixes the OOB symptom but wait_set_event_index_ is still read and written concurrently without synchronization. Should the index be atomic, or should the lifecycle guarantee be enforced another way?

…2376)

is_ready() indexed wait_set.events with wait_set_event_index_, which is only
assigned by add_to_wait_set(). If is_ready() runs before that the member is
uninitialized; if it runs against a different wait set the index belongs to that
other one. Either way the access reads out of bounds and can segfault (observed
with ASan during lifecycle configure).

Initialize wait_set_event_index_ and make is_ready() return false when the index
is not within the wait set's events instead of dereferencing it. Initializing
alone is not sufficient (index 0 may still not be this handler's slot), so the
bounds check is the actual guard.

Adds two regression tests: one calling is_ready() on a handler that was never
added to a wait set, and one where the index was assigned by a different wait set
and equals size_of_events.

Refs ros2#2376

Co-authored-by: Mike Wake <michael.wake@aosgrp.com.au>
Generated-by: Claude Opus 4.8 (Anthropic)
Signed-off-by: Pavel Guzenfeld <pavelguzenfeld@gmail.com>
Signed-off-by: Mike Wake <michael.wake@aosgrp.com.au>
@PavelGuzenfeld
PavelGuzenfeld force-pushed the fix/issue-2376-event-handler-is-ready-bounds branch from 048bc4d to defb18b Compare September 2, 2026 19:02
@PavelGuzenfeld

PavelGuzenfeld commented Sep 2, 2026

Copy link
Copy Markdown
Author

@sylvesterkaczmarek ,

Thanks for the review.

There's no actual race: is_ready() only runs from the executor's wait loop, on the same thread that called add_to_wait_set(), and the index only ever gets written by rcl_wait_set_add_event(). The real bug is simpler - the member gets read before anything assigns it. An atomic wouldn't help with that, or with the stale-index case.

p.s, Also added a test for the index == size_of_events boundary.

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.

2 participants