Skip to content

Commit 94c3909

Browse files
authored
Merge pull request #1766 from zachs18/thread-guard-no-drop-value-on-other-thread
glib: Don't drop `T` if `ThreadGuard<T>` is dropped on the wrong thread.
2 parents 2fcc1f6 + 5829535 commit 94c3909

File tree

1 file changed

+14
-5
lines changed

1 file changed

+14
-5
lines changed

glib/src/thread_guard.rs

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Take a look at the license at the top of the repository in the LICENSE file.
22

33
use std::{
4-
mem, ptr,
4+
mem::ManuallyDrop,
55
sync::atomic::{AtomicUsize, Ordering},
66
};
77
fn next_thread_id() -> usize {
@@ -23,7 +23,9 @@ pub fn thread_id() -> usize {
2323
/// Thread guard that only gives access to the contained value on the thread it was created on.
2424
pub struct ThreadGuard<T> {
2525
thread_id: usize,
26-
value: T,
26+
// This is a `ManuallyDrop` so that the automatic drop glue does not drop `T`
27+
// if this `ThreadGuard` is dropped on the wrong thread.
28+
value: ManuallyDrop<T>,
2729
}
2830

2931
impl<T> ThreadGuard<T> {
@@ -38,7 +40,7 @@ impl<T> ThreadGuard<T> {
3840
pub fn new(value: T) -> Self {
3941
Self {
4042
thread_id: thread_id(),
41-
value,
43+
value: ManuallyDrop::new(value),
4244
}
4345
}
4446

@@ -85,12 +87,16 @@ impl<T> ThreadGuard<T> {
8587
/// created.
8688
#[inline]
8789
pub fn into_inner(self) -> T {
90+
// We wrap `self` in `ManuallyDrop` to defuse `ThreadGuard`'s `Drop` impl.
91+
let mut this = ManuallyDrop::new(self);
92+
8893
assert!(
89-
self.thread_id == thread_id(),
94+
this.thread_id == thread_id(),
9095
"Value accessed from different thread than where it was created"
9196
);
9297

93-
unsafe { ptr::read(&mem::ManuallyDrop::new(self).value) }
98+
// SAFETY: We are on the right thread, and this.value will not be touched after this
99+
unsafe { ManuallyDrop::take(&mut this.value) }
94100
}
95101

96102
// rustdoc-stripper-ignore-next
@@ -108,6 +114,9 @@ impl<T> Drop for ThreadGuard<T> {
108114
self.thread_id == thread_id(),
109115
"Value dropped on a different thread than where it was created"
110116
);
117+
118+
// SAFETY: We are on the right thread, and self.value will not be touched after this
119+
unsafe { ManuallyDrop::drop(&mut self.value) }
111120
}
112121
}
113122

0 commit comments

Comments
 (0)