diff options
| author | Mara Bos <m-ou.se@m-ou.se> | 2022-06-16 11:23:31 +0200 |
|---|---|---|
| committer | Mara Bos <m-ou.se@m-ou.se> | 2022-06-16 12:09:12 +0200 |
| commit | d72294491c5d28449c49b884b620cc24b3cf010f (patch) | |
| tree | a9df2c0fc5270ca3d1188bf63de53246ebad25e6 | |
| parent | 392d2728683f140f6125732240e462c43c5caff4 (diff) | |
| download | rust-d72294491c5d28449c49b884b620cc24b3cf010f.tar.gz rust-d72294491c5d28449c49b884b620cc24b3cf010f.zip | |
Leak pthreax_mutex_t when it's dropped while locked.
| -rw-r--r-- | library/std/src/sys/unix/locks/pthread_mutex.rs | 20 | ||||
| -rw-r--r-- | library/std/src/sys_common/lazy_box.rs | 19 |
2 files changed, 35 insertions, 4 deletions
diff --git a/library/std/src/sys/unix/locks/pthread_mutex.rs b/library/std/src/sys/unix/locks/pthread_mutex.rs index 916e898d890..98afee69ba6 100644 --- a/library/std/src/sys/unix/locks/pthread_mutex.rs +++ b/library/std/src/sys/unix/locks/pthread_mutex.rs @@ -1,5 +1,5 @@ use crate::cell::UnsafeCell; -use crate::mem::MaybeUninit; +use crate::mem::{forget, MaybeUninit}; use crate::sys::cvt_nz; use crate::sys_common::lazy_box::{LazyBox, LazyInit}; @@ -23,6 +23,24 @@ impl LazyInit for Mutex { unsafe { mutex.init() }; mutex } + + fn destroy(mutex: Box<Self>) { + // We're not allowed to pthread_mutex_destroy a locked mutex, + // so check first if it's unlocked. + if unsafe { mutex.try_lock() } { + unsafe { mutex.unlock() }; + drop(mutex); + } else { + // The mutex is locked. This happens if a MutexGuard is leaked. + // In this case, we just leak the Mutex too. + forget(mutex); + } + } + + fn cancel_init(_: Box<Self>) { + // In this case, we can just drop it without any checks, + // since it cannot have been locked yet. + } } impl Mutex { diff --git a/library/std/src/sys_common/lazy_box.rs b/library/std/src/sys_common/lazy_box.rs index 647c13d2437..63c3316bdeb 100644 --- a/library/std/src/sys_common/lazy_box.rs +++ b/library/std/src/sys_common/lazy_box.rs @@ -21,8 +21,21 @@ pub(crate) trait LazyInit { /// /// It might be called more than once per LazyBox, as multiple threads /// might race to initialize it concurrently, each constructing and initializing - /// their own box. (All but one of them will be destroyed right after.) + /// their own box. All but one of them will be passed to `cancel_init` right after. fn init() -> Box<Self>; + + /// Any surplus boxes from `init()` that lost the initialization race + /// are passed to this function for disposal. + /// + /// The default implementation calls destroy(). + fn cancel_init(x: Box<Self>) { + Self::destroy(x); + } + + /// This is called to destroy a used box. + /// + /// The default implementation just drops it. + fn destroy(_: Box<Self>) {} } impl<T: LazyInit> LazyBox<T> { @@ -45,7 +58,7 @@ impl<T: LazyInit> LazyBox<T> { Err(ptr) => { // Lost the race to another thread. // Drop the box we created, and use the one from the other thread instead. - drop(unsafe { Box::from_raw(new_ptr) }); + T::cancel_init(unsafe { Box::from_raw(new_ptr) }); ptr } } @@ -71,7 +84,7 @@ impl<T: LazyInit> Drop for LazyBox<T> { fn drop(&mut self) { let ptr = *self.ptr.get_mut(); if !ptr.is_null() { - drop(unsafe { Box::from_raw(ptr) }); + T::destroy(unsafe { Box::from_raw(ptr) }); } } } |
