- Notifications
You must be signed in to change notification settings - Fork 174
Description
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:
ros2_rust/rosidl_runtime_rs/src/sequence.rs
Lines 510 to 515 in ede2291
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