-
Notifications
You must be signed in to change notification settings - Fork 169
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