Skip to content

Panic occurs when publish sequence types for Rust 1.78 #406

@Oscarchoi

Description

@Oscarchoi

I found that, in Rust 1.78, when trying to publish data of sequence types, such as std_msgs::msg::UInt8MultiArray or messages utilizing sensor_msgs::msg::PointCloud2, a panic occurs with the message:
unsafe precondition(s) violated: ptr::write_bytes requires that the destination pointer is aligned and non-null.

I tested ros2-rust 0.4.1 on ubuntu 22.04.1 + ros2 humble and checked on ubuntu 20.04.6 + ros2 foxy, too.
The source code I tested and the backtrace message are as follows:

source
use rclrs::{Context, Node}; fn main() { let context = Context::new([]).expect("failed to create context"); let node = Node::new(&context, "rust_ros2_node").expect("failed to create node"); let publisher = node .create_publisher::<std_msgs::msg::UInt8MultiArray>("u8_array", rclrs::QOS_PROFILE_DEFAULT) .expect("failed to create publisher"); let layout = std_msgs::msg::MultiArrayLayout { dim: [ std_msgs::msg::MultiArrayDimension { label: String::from("x"), size: 1, stride: 1, }, std_msgs::msg::MultiArrayDimension { label: String::from("y"), size: 1, stride: 1, }, std_msgs::msg::MultiArrayDimension { label: String::from("z"), size: 1, stride: 1, }, ] .to_vec(), data_offset: 0, }; let msg = std_msgs::msg::UInt8MultiArray { layout, data: vec![0u8, 1, 2], }; publisher.publish(msg).expect("failed to publish message"); println!("Published"); } 
backtrace
$ ~/Workspace/rclrs-tutorial/sequence$ cargo run Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.06s Running `target/debug/sequence` thread 'main' panicked at library/core/src/panicking.rs:156:5: unsafe precondition(s) violated: ptr::write_bytes requires that the destination pointer is aligned and non-null stack backtrace: 0: rust_begin_unwind at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library/std/src/panicking.rs:645:5 1: core::panicking::panic_nounwind_fmt::runtime at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library/core/src/panicking.rs:110:18 2: core::panicking::panic_nounwind_fmt at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library/core/src/panicking.rs:123:9 3: core::panicking::panic_nounwind at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library/core/src/panicking.rs:156:5 4: core::intrinsics::write_bytes::precondition_check at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library/core/src/intrinsics.rs:2799:21 5: core::intrinsics::write_bytes at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library/core/src/intrinsics.rs:3154:9 6: rosidl_runtime_rs::sequence::<impl rosidl_runtime_rs::traits::SequenceAlloc for u8>::sequence_init at /home/oscarchoi/.cargo/registry/src/index.crates.io-6f17d22bba15001f/rosidl_runtime_rs-0.4.1/src/sequence.rs:512:21 7: rosidl_runtime_rs::sequence::Sequence<T>::new at /home/oscarchoi/.cargo/registry/src/index.crates.io-6f17d22bba15001f/rosidl_runtime_rs-0.4.1/src/sequence.rs:252:13 8: <rosidl_runtime_rs::sequence::Sequence<T> as core::iter::traits::collect::FromIterator<T>>::from_iter at /home/oscarchoi/.cargo/registry/src/index.crates.io-6f17d22bba15001f/rosidl_runtime_rs-0.4.1/src/sequence.rs:202:23 9: <rosidl_runtime_rs::sequence::Sequence<T> as core::convert::From<alloc::vec::Vec<T>>>::from at /home/oscarchoi/.cargo/registry/src/index.crates.io-6f17d22bba15001f/rosidl_runtime_rs-0.4.1/src/sequence.rs:193:9 10: <T as core::convert::Into<U>>::into at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library/core/src/convert/mod.rs:759:9 11: <std_msgs::msg::UInt8MultiArray as rosidl_runtime_rs::traits::Message>::into_rmw_message at /home/oscarchoi/ros2_ws/install/std_msgs/share/std_msgs/rust/src/msg.rs:3142:15 12: rclrs::publisher::Publisher<T>::publish at /home/oscarchoi/.cargo/registry/src/index.crates.io-6f17d22bba15001f/rclrs-0.4.1/src/publisher.rs:148:27 13: sequence::main at ./src/main.rs:38:5 14: core::ops::function::FnOnce::call_once at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library/core/src/ops/function.rs:250:5 note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace. thread caused non-unwinding panic. aborting. Aborted (core dumped)

It seems that the panic arises at the following location:

unsafe {
// This allocates space and sets seq.size and seq.capacity to size
let ret = $init_func(seq as *mut _, size);
// Zero memory, since it will be uninitialized if there is no default value
std::ptr::write_bytes(seq.data, 0u8, size);
ret

In the current implementation, if the size is 0 (which happens when initialization), it's expected that seq.data will be null. However, according to the latest std documentation (https://doc.rust-lang.org/nightly/std/ptr/fn.write_bytes.html), even if the number of bytes being written is 0, the pointer should not be null. I believe this is causing the panic.

It seems that a null pointer is inevitable when the size is 0, due to the implementation of rosidl_runtime (https://github.com/ros2/rosidl/blob/4ba0effa201030ae8f45597b29d4ca685b2d50a1/rosidl_runtime_c/src/primitives_sequence_functions.c#L24-L43).

I'm quite new to rust and not sure what the correct solution is, I found that adding a null check before the write_bytes prevents the panic and makes the publish work. Oscarchoi@8b1e786

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions