diff --git a/Cargo.toml b/Cargo.toml index 85cadba..c555fcb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,7 @@ categories = ["concurrency", "no-std", "rust-patterns"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +maybe-dangling = "0.1.2" [dev-dependencies] once_cell = "1.8.0" diff --git a/src/lib.rs b/src/lib.rs index 3e38d4b..c512602 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -104,9 +104,9 @@ #![no_std] use core::{ cell::UnsafeCell, - mem::ManuallyDrop, sync::atomic::{AtomicBool, Ordering}, }; +use maybe_dangling::ManuallyDrop; /// A cell type which value can be taken only once. /// @@ -320,6 +320,8 @@ unsafe impl Sync for TakeCell {} #[derive(Default)] pub struct TakeOwnCell( // Invariant: `TakeCell::taken` is true <=> `ManuallyDrop`'s value was taken + // Note that we're using `ManuallyDrop` from the `maybe-dangling` crate, + // in order to avoid the unsoundness in https://github.com/WaffleLapkin/takecell/issues/5 TakeCell>, ); @@ -602,6 +604,8 @@ mod tests { #[cfg(test)] mod own_tests { use crate::TakeOwnCell; + extern crate alloc; + use alloc::boxed::Box; #[test] fn it_works() { @@ -659,4 +663,19 @@ mod own_tests { assert!(cell.take().is_none()); assert!(cell.into_inner().is_none()); } + + // Moving an empty `TakeOwnCell` should not assert validity or ownership + // of its former contents. + // See https://github.com/WaffleLapkin/takecell/issues/5 + #[test] + fn maybe_dangling() { + let cell = TakeOwnCell::new(Box::new(1)); + let data = cell.take().unwrap(); + // Moving the cell does not invalidate the data + let cell = cell; + assert_eq!(*data, 1); + // Dropping the data does not invalidate the cell + drop(data); + let _cell = cell; + } }