diff --git a/r2r/src/clients.rs b/r2r/src/clients.rs index 67d2d68..2b52674 100644 --- a/r2r/src/clients.rs +++ b/r2r/src/clients.rs @@ -318,11 +318,10 @@ impl Client_ for UntypedClient_ { } } -pub fn create_client_helper( - node: *mut rcl_node_t, service_name: &str, service_ts: *const rosidl_service_type_support_t, - qos_profile: QosProfile, -) -> Result { - let mut client_handle = unsafe { rcl_get_zero_initialized_client() }; +pub unsafe fn create_client_helper( + client_handle: &mut rcl_client_t, node: *mut rcl_node_t, service_name: &str, + service_ts: *const rosidl_service_type_support_t, qos_profile: QosProfile, +) -> Result<()> { let service_name_c_string = CString::new(service_name).map_err(|_| Error::RCL_RET_INVALID_ARGUMENT)?; @@ -330,15 +329,16 @@ pub fn create_client_helper( let mut client_options = rcl_client_get_default_options(); client_options.qos = qos_profile.into(); rcl_client_init( - &mut client_handle, + client_handle, node, service_ts, service_name_c_string.as_ptr(), &client_options, ) }; + if result == RCL_RET_OK as i32 { - Ok(client_handle) + Ok(()) } else { Err(Error::from_rcl_error(result)) } diff --git a/r2r/src/nodes.rs b/r2r/src/nodes.rs index b56f564..ef4d9a4 100644 --- a/r2r/src/nodes.rs +++ b/r2r/src/nodes.rs @@ -849,19 +849,30 @@ impl Node { where T: WrappedServiceTypeSupport, { - let client_handle = create_client_helper( - self.node_handle.as_mut(), - service_name, - T::get_ts(), - qos_profile, - )?; - let ws = TypedClient:: { - rcl_handle: client_handle, + // SAFETY: The `rcl_handle` is zero initialized (partial initialization) in this block. + let mut client_arc = Arc::new(Mutex::new(TypedClient:: { + rcl_handle: unsafe { rcl_get_zero_initialized_client() }, response_channels: Vec::new(), poll_available_channels: Vec::new(), + })); + let client_ref = Arc::get_mut(&mut client_arc) + .unwrap() // No other Arc should exist. The Arc was just created. + .get_mut() + .unwrap(); // The mutex was just created. It should not be poisoned. + + // SAFETY: + // The client was zero initialized above. + // Full initialization happens in `create_client_helper`. + unsafe { + create_client_helper( + &mut client_ref.rcl_handle, + self.node_handle.as_mut(), + service_name, + T::get_ts(), + qos_profile, + )?; }; - let client_arc = Arc::new(Mutex::new(ws)); let c = make_client(Arc::downgrade(&client_arc)); self.clients.push(client_arc); Ok(c) @@ -877,20 +888,32 @@ impl Node { &mut self, service_name: &str, service_type: &str, qos_profile: QosProfile, ) -> Result { let service_type = UntypedServiceSupport::new_from(service_type)?; - let client_handle = create_client_helper( - self.node_handle.as_mut(), - service_name, - service_type.ts, - qos_profile, - )?; - let client = UntypedClient_ { + + // SAFETY: The `rcl_handle` is zero initialized (partial initialization) in this block. + let mut client_arc = Arc::new(Mutex::new(UntypedClient_ { service_type, - rcl_handle: client_handle, + rcl_handle: unsafe { rcl_get_zero_initialized_client() }, response_channels: Vec::new(), poll_available_channels: Vec::new(), + })); + let client_ref = Arc::get_mut(&mut client_arc) + .unwrap() // No other Arc should exist. The Arc was just created. + .get_mut() + .unwrap(); // The mutex was just created. It should not be poisoned. + + // SAFETY: + // The client was zero initialized above. + // Full initialization happens in `create_client_helper`. + unsafe { + create_client_helper( + &mut client_ref.rcl_handle, + self.node_handle.as_mut(), + service_name, + client_ref.service_type.ts, + qos_profile, + )?; }; - let client_arc = Arc::new(Mutex::new(client)); let c = make_untyped_client(Arc::downgrade(&client_arc)); self.clients.push(client_arc); Ok(c)