Skip to content

Commit f30a284

Browse files
committed
Ensure that mutex guards are not being dropped prematurely
Signed-off-by: Michael X. Grey <[email protected]>
1 parent 81c065e commit f30a284

File tree

7 files changed

+78
-60
lines changed

7 files changed

+78
-60
lines changed

rclrs/src/client.rs

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,10 @@ impl ClientHandle {
3131
impl Drop for ClientHandle {
3232
fn drop(&mut self) {
3333
let rcl_client = self.rcl_client.get_mut().unwrap();
34-
let rcl_node = &mut *self.node_handle.rcl_node.lock().unwrap();
34+
let mut rcl_node = self.node_handle.rcl_node.lock().unwrap();
3535
// SAFETY: No preconditions for this function
3636
unsafe {
37-
rcl_client_fini(rcl_client, rcl_node);
37+
rcl_client_fini(rcl_client, &mut *rcl_node);
3838
}
3939
}
4040
}
@@ -97,14 +97,17 @@ where
9797
// The rcl_node is kept alive because it is co-owned by the client.
9898
// The topic name and the options are copied by this function, so they can be dropped
9999
// afterwards.
100-
rcl_client_init(
101-
&mut rcl_client,
102-
&*node_handle.rcl_node.lock().unwrap(),
103-
type_support,
104-
topic_c_string.as_ptr(),
105-
&client_options,
106-
)
107-
.ok()?;
100+
{
101+
let mut rcl_node = node_handle.rcl_node.lock().unwrap();
102+
rcl_client_init(
103+
&mut rcl_client,
104+
&mut *rcl_node,
105+
type_support,
106+
topic_c_string.as_ptr(),
107+
&client_options,
108+
)
109+
.ok()?;
110+
}
108111
}
109112

110113
let handle = Arc::new(ClientHandle {

rclrs/src/node.rs

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,9 @@ use crate::rcl_bindings::*;
1515
use crate::{
1616
Client, ClientBase, Clock, Context, GuardCondition, ParameterBuilder, ParameterInterface,
1717
ParameterVariant, Parameters, Publisher, QoSProfile, RclrsError, Service, ServiceBase,
18-
Subscription, SubscriptionBase, SubscriptionCallback, TimeSource, ToResult, ContextHandle,
18+
Subscription, SubscriptionBase, SubscriptionCallback, TimeSource, ContextHandle,
1919
};
2020

21-
impl Drop for rcl_node_t {
22-
fn drop(&mut self) {
23-
// SAFETY: No preconditions for this function
24-
unsafe { rcl_node_fini(self).ok().unwrap() };
25-
}
26-
}
27-
2821
// SAFETY: The functions accessing this type, including drop(), shouldn't care about the thread
2922
// they are running in. Therefore, this type can be safely sent to another thread.
3023
unsafe impl Send for rcl_node_t {}
@@ -81,6 +74,14 @@ pub(crate) struct NodeHandle {
8174
pub(crate) context_handle: Arc<ContextHandle>,
8275
}
8376

77+
impl Drop for NodeHandle {
78+
fn drop(&mut self) {
79+
let _context_lock = self.context_handle.rcl_context.lock().unwrap();
80+
let mut rcl_node = self.rcl_node.lock().unwrap();
81+
unsafe { rcl_node_fini(&mut *rcl_node) };
82+
}
83+
}
84+
8485
impl Eq for Node {}
8586

8687
impl PartialEq for Node {
@@ -185,7 +186,8 @@ impl Node {
185186
&self,
186187
getter: unsafe extern "C" fn(*const rcl_node_t) -> *const c_char,
187188
) -> String {
188-
unsafe { call_string_getter_with_handle(&self.handle.rcl_node.lock().unwrap(), getter) }
189+
let rcl_node = self.handle.rcl_node.lock().unwrap();
190+
unsafe { call_string_getter_with_handle(&rcl_node, getter) }
189191
}
190192

191193
/// Creates a [`Client`][1].
@@ -361,11 +363,11 @@ impl Node {
361363
// add description about this function is for getting actual domain_id
362364
// and about override of domain_id via node option
363365
pub fn domain_id(&self) -> usize {
364-
let rcl_node = &*self.handle.rcl_node.lock().unwrap();
366+
let rcl_node = self.handle.rcl_node.lock().unwrap();
365367
let mut domain_id: usize = 0;
366368
let ret = unsafe {
367369
// SAFETY: No preconditions for this function.
368-
rcl_node_get_domain_id(rcl_node, &mut domain_id)
370+
rcl_node_get_domain_id(&*rcl_node, &mut domain_id)
369371
};
370372

371373
debug_assert_eq!(ret, 0);

rclrs/src/node/builder.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -284,11 +284,14 @@ impl NodeBuilder {
284284
rcl_node: Mutex::new(rcl_node),
285285
context_handle: Arc::clone(&self.context),
286286
});
287-
let parameter = ParameterInterface::new(
288-
&*handle.rcl_node.lock().unwrap(),
289-
&rcl_node_options.arguments,
290-
&rcl_context.global_arguments,
291-
)?;
287+
let parameter = {
288+
let rcl_node = handle.rcl_node.lock().unwrap();
289+
ParameterInterface::new(
290+
&*rcl_node,
291+
&rcl_node_options.arguments,
292+
&rcl_context.global_arguments,
293+
)?
294+
};
292295
let node = Arc::new(Node {
293296
handle,
294297
clients_mtx: Mutex::new(vec![]),

rclrs/src/node/graph.rs

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -137,8 +137,9 @@ impl Node {
137137

138138
// SAFETY: rcl_names_and_types is zero-initialized as expected by this call
139139
unsafe {
140+
let rcl_node = self.handle.rcl_node.lock().unwrap();
140141
rcl_get_topic_names_and_types(
141-
&*self.handle.rcl_node.lock().unwrap(),
142+
&*rcl_node,
142143
&mut rcutils_get_default_allocator(),
143144
false,
144145
&mut rcl_names_and_types,
@@ -166,8 +167,9 @@ impl Node {
166167

167168
// SAFETY: node_names and node_namespaces are zero-initialized as expected by this call.
168169
unsafe {
170+
let rcl_node = self.handle.rcl_node.lock().unwrap();
169171
rcl_get_node_names(
170-
&*self.handle.rcl_node.lock().unwrap(),
172+
&*rcl_node,
171173
rcutils_get_default_allocator(),
172174
&mut rcl_names,
173175
&mut rcl_namespaces,
@@ -213,8 +215,9 @@ impl Node {
213215

214216
// SAFETY: The node_names, namespaces, and enclaves are zero-initialized as expected by this call.
215217
unsafe {
218+
let rcl_node = self.handle.rcl_node.lock().unwrap();
216219
rcl_get_node_names_with_enclaves(
217-
&*self.handle.rcl_node.lock().unwrap(),
220+
&*rcl_node,
218221
rcutils_get_default_allocator(),
219222
&mut rcl_names,
220223
&mut rcl_namespaces,
@@ -262,8 +265,9 @@ impl Node {
262265

263266
// SAFETY: The topic_name string was correctly allocated previously
264267
unsafe {
268+
let rcl_node = self.handle.rcl_node.lock().unwrap();
265269
rcl_count_publishers(
266-
&*self.handle.rcl_node.lock().unwrap(),
270+
&*rcl_node,
267271
topic_name.as_ptr(),
268272
&mut count,
269273
)
@@ -282,8 +286,9 @@ impl Node {
282286

283287
// SAFETY: The topic_name string was correctly allocated previously
284288
unsafe {
289+
let rcl_node = self.handle.rcl_node.lock().unwrap();
285290
rcl_count_subscribers(
286-
&*self.handle.rcl_node.lock().unwrap(),
291+
&*rcl_node,
287292
topic_name.as_ptr(),
288293
&mut count,
289294
)
@@ -336,8 +341,9 @@ impl Node {
336341

337342
// SAFETY: node_name and node_namespace have been zero-initialized.
338343
unsafe {
344+
let rcl_node = self.handle.rcl_node.lock().unwrap();
339345
getter(
340-
&*self.handle.rcl_node.lock().unwrap(),
346+
&*rcl_node,
341347
&mut rcutils_get_default_allocator(),
342348
node_name.as_ptr(),
343349
node_namespace.as_ptr(),
@@ -371,8 +377,9 @@ impl Node {
371377

372378
// SAFETY: topic has been zero-initialized
373379
unsafe {
380+
let rcl_node = self.handle.rcl_node.lock().unwrap();
374381
getter(
375-
&*self.handle.rcl_node.lock().unwrap(),
382+
&*rcl_node,
376383
&mut rcutils_get_default_allocator(),
377384
topic.as_ptr(),
378385
false,
@@ -458,14 +465,16 @@ fn convert_names_and_types(
458465
#[cfg(test)]
459466
mod tests {
460467
use super::*;
461-
use crate::Context;
468+
use crate::{Context, InitOptions};
462469

463470
#[test]
464471
fn test_graph_empty() {
465-
let context = Context::new([]).unwrap();
472+
let context = Context::new_with_options(
473+
[],
474+
InitOptions::new().with_domain_id(Some(99))
475+
).unwrap();
466476
let node_name = "test_publisher_names_and_types";
467477
let node = Node::new(&context, node_name).unwrap();
468-
469478
// Test that the graph has no publishers
470479
let names_and_topics = node
471480
.get_publisher_names_and_types_by_node(node_name, "")

rclrs/src/publisher.rs

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,19 @@ struct PublisherHandle {
2323
node_handle: Arc<NodeHandle>,
2424
}
2525

26+
impl Drop for PublisherHandle {
27+
fn drop(&mut self) {
28+
unsafe {
29+
// SAFETY: No preconditions for this function (besides the arguments being valid).
30+
let mut rcl_node = self.node_handle.rcl_node.lock().unwrap();
31+
rcl_publisher_fini(
32+
self.rcl_publisher.get_mut().unwrap(),
33+
&mut *rcl_node,
34+
);
35+
}
36+
}
37+
}
38+
2639
/// Struct for sending messages of type `T`.
2740
///
2841
/// Multiple publishers can be created for the same topic, in different nodes or the same node.
@@ -44,21 +57,6 @@ where
4457
handle: PublisherHandle,
4558
}
4659

47-
impl<T> Drop for Publisher<T>
48-
where
49-
T: Message,
50-
{
51-
fn drop(&mut self) {
52-
unsafe {
53-
// SAFETY: No preconditions for this function (besides the arguments being valid).
54-
rcl_publisher_fini(
55-
self.handle.rcl_publisher.get_mut().unwrap(),
56-
&mut *self.handle.node_handle.rcl_node.lock().unwrap(),
57-
);
58-
}
59-
}
60-
}
61-
6260
// SAFETY: The functions accessing this type, including drop(), shouldn't care about the thread
6361
// they are running in. Therefore, this type can be safely sent to another thread.
6462
unsafe impl<T> Send for Publisher<T> where T: Message {}
@@ -99,9 +97,10 @@ where
9997
// The topic name and the options are copied by this function, so they can be dropped
10098
// afterwards.
10199
// TODO: type support?
100+
let rcl_node = node_handle.rcl_node.lock().unwrap();
102101
rcl_publisher_init(
103102
&mut rcl_publisher,
104-
&*node_handle.rcl_node.lock().unwrap(),
103+
&*rcl_node,
105104
type_support_ptr,
106105
topic_c_string.as_ptr(),
107106
&publisher_options,

rclrs/src/service.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,10 @@ impl ServiceHandle {
2929
impl Drop for ServiceHandle {
3030
fn drop(&mut self) {
3131
let rcl_service = self.rcl_service.get_mut().unwrap();
32-
let rcl_node = &mut *self.node_handle.rcl_node.lock().unwrap();
32+
let mut rcl_node = self.node_handle.rcl_node.lock().unwrap();
3333
// SAFETY: No preconditions for this function
3434
unsafe {
35-
rcl_service_fini(rcl_service, rcl_node);
35+
rcl_service_fini(rcl_service, &mut *rcl_node);
3636
}
3737
}
3838
}
@@ -99,9 +99,10 @@ where
9999
// The rcl_node is kept alive because it is co-owned by the service.
100100
// The topic name and the options are copied by this function, so they can be dropped
101101
// afterwards.
102+
let rcl_node = node_handle.rcl_node.lock().unwrap();
102103
rcl_service_init(
103104
&mut rcl_service,
104-
&*node_handle.rcl_node.lock().unwrap(),
105+
&*rcl_node,
105106
type_support,
106107
topic_c_string.as_ptr(),
107108
&service_options as *const _,

rclrs/src/subscription.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,10 @@ impl SubscriptionHandle {
3737
impl Drop for SubscriptionHandle {
3838
fn drop(&mut self) {
3939
let rcl_subscription = self.rcl_subscription.get_mut().unwrap();
40-
let rcl_node = &mut *self.node_handle.rcl_node.lock().unwrap();
40+
let mut rcl_node = self.node_handle.rcl_node.lock().unwrap();
4141
// SAFETY: No preconditions for this function (besides the arguments being valid).
4242
unsafe {
43-
rcl_subscription_fini(rcl_subscription, rcl_node);
43+
rcl_subscription_fini(rcl_subscription, &mut *rcl_node);
4444
}
4545
}
4646
}
@@ -85,7 +85,7 @@ where
8585
{
8686
/// Creates a new subscription.
8787
pub(crate) fn new<Args>(
88-
rcl_node: Arc<NodeHandle>,
88+
node_handle: Arc<NodeHandle>,
8989
topic: &str,
9090
qos: QoSProfile,
9191
callback: impl SubscriptionCallback<T, Args>,
@@ -113,9 +113,10 @@ where
113113
// The topic name and the options are copied by this function, so they can be dropped
114114
// afterwards.
115115
// TODO: type support?
116+
let rcl_node = node_handle.rcl_node.lock().unwrap();
116117
rcl_subscription_init(
117118
&mut rcl_subscription,
118-
&*rcl_node.rcl_node.lock().unwrap(),
119+
&*rcl_node,
119120
type_support,
120121
topic_c_string.as_ptr(),
121122
&subscription_options,
@@ -125,7 +126,7 @@ where
125126

126127
let handle = Arc::new(SubscriptionHandle {
127128
rcl_subscription: Mutex::new(rcl_subscription),
128-
node_handle: rcl_node,
129+
node_handle,
129130
in_use_by_wait_set: Arc::new(AtomicBool::new(false)),
130131
});
131132

0 commit comments

Comments
 (0)