Skip to content

Fix incorrect internal clear inside RingBufferImplemenetation#3116

Open
InvincibleRMC wants to merge 1 commit intorollingfrom
rmc/fix-UB-ubuntu26
Open

Fix incorrect internal clear inside RingBufferImplemenetation#3116
InvincibleRMC wants to merge 1 commit intorollingfrom
rmc/fix-UB-ubuntu26

Conversation

@InvincibleRMC
Copy link
Copy Markdown
Contributor

Description

ros2/ci#838 (comment)
Calling the internal clear could lead to index out of bounds. Caught with gcc15 on Ubuntu26.

Is this user-facing behavior change?

Did you use Generative AI?

Additional Information

Signed-off-by: Michael Carlstrom <rmc@carlstrom.com>
@InvincibleRMC
Copy link
Copy Markdown
Contributor Author

InvincibleRMC commented Mar 30, 2026

Pulls: #3116
Gist: https://gist.githubusercontent.com/InvincibleRMC/0d8a5e5c5756944635432d3678645627/raw/c580dbba3a492d3a30f0711d9d97f930b97c3644/ros2.repos
BUILD args: --continue-on-error --packages-above-and-dependencies rclcpp
TEST args: --packages-above rclcpp
ROS Distro: rolling
Job: ci_launcher
ci_launcher ran: https://ci.ros2.org/job/ci_launcher/18730

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

Rebuild linux
Build Status

Copy link
Copy Markdown
Collaborator

@fujitatomoya fujitatomoya left a comment

Choose a reason for hiding this comment

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

i think this is right thing to do.
the ring buffer's design relies on this vector staying at a fixed size equal to capacity_ to logically track which elements are valid. calling std::vector::clear() sets the vector's size to 0 and deallocates elements, which breaks the class invariant that ring_buffer_.size() == capacity_. after a clear() call on the old code, any subsequent enqueue() would index into ring_buffer_[write_index_] on a now-empty vector — that's undefined behavior (out-of-bounds access).

can we also consider to add the regression test verifies this undefined behavior?

this actually rolls back part of #2837

@mjcarroll
Copy link
Copy Markdown
Member

Agree with @fujitatomoya's summary and also second adding a test just to make sure that we don't regress here.

@InvincibleRMC
Copy link
Copy Markdown
Contributor Author

InvincibleRMC commented Mar 31, 2026

Yeah will try to come up with UB test. This definitely raises the question of what does clearing a ring buffer really mean. Since the current implementation doesn't support any resizing methods I don't think destroying the internal buffer makes sense and should maybe even be std::array instead.

Does rclcpp have some convention on how to acess private fields for tests? friend class, compile time constant, something else?

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