Skip to content

robostack-lyrical ships rosidl_runtime_c (5.2.1) with rosidl_buffer-extended primitive sequences, but Rust bindings use the 24-byte layout → rclrs nodes corrupt/segfault on primitive-sequence messages #17

Description

@rosterloh

Solution to issue cannot be found in the documentation.

  • I checked the documentation.

Issue

Summary

ros-lyrical-rosidl-runtime-c 5.2.1 defines primitive sequences with the rosidl_buffer extension (is_rosidl_buffer/owns_rosidl_buffer → 32-byte struct), but the Rust bindings used in the same channel (ros-lyrical-rosidl-generator-rs 5.2.1 + rosidl_runtime_rs 0.6.0) use the standard 24-byte Sequence<T>. The C and Rust ABIs therefore disagree for every primitive-sequence field, so any rclrs node silently corrupts or segfaults on such messages.

Environment

robostack-lyrical (linux-64); ros-lyrical-rosidl-runtime-c 5.2.1 (build np2py314…_22), ros-lyrical-rosidl-generator-rs 5.2.1; rosidl_runtime_rs 0.6.0; rclrs 0.7; rustc 1.97.0, edition 2024.

Root cause

This channel's primitives_sequence.h gives primitive sequences two extra trailing fields:

<T>* data; size_t size; size_t capacity;         // 0 / 8 / 16
bool is_rosidl_buffer;  bool owns_rosidl_buffer;  // 24 / 25 -> struct padded to 32

rosidl_runtime_rs::Sequence<T> is the standard 24-byte, 3-field struct for all T.

C type C size Rust Sequence<T>
uint8__Sequence / double__Sequence (primitive) 32 24
Point__Sequence / ColorRGBA__Sequence (message) 24 24

Measured (gcc sizeof/offsetof on the installed headers vs Rust size_of/offset_of): primitive sequences 32 vs 24; visualization_msgs/Marker C sizeof 480 vs Rust 464, agreeing through texture (offset 256) then shifting +8 at uv_coordinates/text/mesh_resource — introduced by the primitive CompressedImage.data sequence (C CompressedImage 88 vs Rust 80).

Symptom

Marker::default() round-trips via from_rmw_message, .to_string()-ing text at the shifted offset:

debug:   panic: slice::from_raw_parts requires the pointer to be aligned and non-null
release: SIGSEGV (invalid memory reference)
  <String as Display>::fmt        rosidl_runtime_rs-0.6.0/src/string.rs:187
  Marker::from_rmw_message        visualization_msgs/rust/src/msg.rs:1133  (field: text)
  Marker::default                 visualization_msgs/rust/src/msg.rs:1035

Same corruption for any primitive sequence with fields after it — sensor_msgs/JointState (velocity/effort), trajectory_msgs/JointTrajectoryPoint (positions). Benign only when the misread lands on zeroed empty-default memory.

Upstream comparison

ros2/rosidl master primitives_sequence.h has only data/size/capacity, so this is specific to packages built with the rosidl_buffer extension in this channel.

Ask

Is the Rust binding set in robostack-lyrical expected to be ABI-consistent with these rosidl_buffer-extended C sequences? If so, the shipped Rust runtime/generator needs to model the 32-byte primitive layout; if the extension is unintended for this channel, the C packages need rebuilding without it.

Upstream Rust tracking: ros2-rust/ros2_rust#659

Installed packages

$ pixi list --explicit
Installed for: linux-64
Name                             Version  Build                      Size  Kind   Source
ccache                           4.13.6   hedf47ba_0           835.64 KiB  conda  https://prefix.dev/conda-forge
clangdev                         22.1.8   default_h1b9a2e9_3    59.08 MiB  conda  https://prefix.dev/conda-forge
cmake                            4.4.0    hc85cc9f_0            22.56 MiB  conda  https://prefix.dev/conda-forge
colcon-common-extensions         0.3.0    py314hdafbbf9_4       12.82 KiB  conda  https://prefix.dev/conda-forge
colcon-mixin                     0.2.3    pyhd8ed1ab_1          24.56 KiB  conda  https://prefix.dev/conda-forge
colcon_cargo                     0.2.0                                     pypi   https://pypi.org/simple
colcon_ros_cargo                 0.2.0                                     pypi   https://pypi.org/simple
compilers                        1.11.0   ha770c72_0             7.31 KiB  conda  https://prefix.dev/conda-forge
curl                             8.21.0   hae6b9f4_2           190.21 KiB  conda  https://prefix.dev/conda-forge
filelock                         3.29.7   pyhd8ed1ab_0          38.72 KiB  conda  https://prefix.dev/conda-forge
libcurl                          8.21.0   hae6b9f4_2           469.07 KiB  conda  https://prefix.dev/conda-forge
lld                              22.1.8   hef48ded_0            11.84 MiB  conda  https://prefix.dev/conda-forge
ninja                            1.13.2   h171cf75_0           181.96 KiB  conda  https://prefix.dev/conda-forge
patch                            2.8      hb03c661_1002        114.47 KiB  conda  https://prefix.dev/conda-forge
pkg-config                       0.29.2   h4bc722e_1009        112.48 KiB  conda  https://prefix.dev/conda-forge
python                           3.14.6   habeac84_100_cp314    35.02 MiB  conda  https://prefix.dev/conda-forge
ros-lyrical-rmw-zenoh-cpp        0.10.4   np2py314h19ba983_22  350.58 KiB  conda  https://prefix.dev/robostack-lyrical
ros-lyrical-ros-base             0.13.0   np2py314hb48eaa3_22   21.67 KiB  conda  https://prefix.dev/robostack-lyrical
ros-lyrical-rosidl-generator-rs  0.4.12   np2py314hb48eaa3_22   47.02 KiB  conda  https://prefix.dev/robostack-lyrical
rust                             1.97.0   h53717f1_0           165.58 MiB  conda  https://prefix.dev/conda-forge
vcstool                          1.1.7    hd8ed1ab_0            10.24 KiB  conda  https://prefix.dev/conda-forge

Environment info

System
------------
       Pixi version: 0.73.0
        TLS backend: rustls
           Platform: linux-64
   Virtual packages: __unix=0=0
                   : __linux=7.0.2=0
                   : __glibc=2.41=0
                   : __archspec=1=x86_64_v4
          Cache dir: /root/.cache/rattler/cache
       Auth storage: /root/.rattler/credentials.json
   Config locations: No config files found

Global
------------
            Bin dir: /root/.pixi/bin
    Environment dir: /root/.pixi/envs
       Manifest dir: /root/.pixi/manifests/pixi-global.toml

Workspace
------------
               Name: eit_robot
            Version: 1.0.0
      Manifest file: /root/eit/eit_robot/pixi.toml
       Last updated: 21-07-2026 11:36:59

Environments
------------
        Environment: default
           Features: linux, default
           Channels: https://prefix.dev/pixi-build-backends, https://prefix.dev/conda-forge, https://prefix.dev/robostack-lyrical
   Dependency count: 19
       Dependencies: python, rust, ros-lyrical-ros-base, ros-lyrical-rmw-zenoh-cpp, ros-lyrical-rosidl-generator-rs, colcon-common-extensions, colcon-mixin, compilers, cmake, ninja, pkg-config, libcurl, filelock, ccache, lld, curl, clangdev, patch, vcstool
  PyPI Dependencies: colcon-cargo, colcon-ros-cargo
   Target platforms: linux-aarch64, linux-64
  Resolved platform: linux-64 (archspec=x86_64, glibc=2.28, linux=4.18, __unix)
   Minimum platform: linux-64 (glibc=2.28, __unix)
    Prefix location: /root/eit/eit_robot/.pixi/envs/default
              Tasks: colcon_mixin_setup, update_deps, build_clean, test_teleop, test_capture_kinematics, clean, pytests, test, test_capture_solver, setup, test_teleop_pure, test_capture_executor, test_control, setup_ros_rust, test_capture_interfaces, build

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions