From dd59b1fb4c66089c10b7e189975aeb171085312e Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 7 May 2015 10:49:39 -0700 Subject: [PATCH] std: Mark `mem::forget` as a safe function This commit is an implementation of [RFC 1066][rfc] where the conclusion was that leaking a value is a safe operation in Rust code, so updating the signature of this function follows suit. [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/1066-safe-mem-forget.md Closes #25186 --- src/libcollections/vec.rs | 4 +-- src/libcore/intrinsics.rs | 4 --- src/libcore/mem.rs | 51 ++++++++++++++++++++++++++++---- src/libstd/sys/unix/fd.rs | 2 +- src/libstd/sys/windows/handle.rs | 2 +- 5 files changed, 49 insertions(+), 14 deletions(-) diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index a2be8b81219..9bf7ef0df38 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -647,7 +647,7 @@ impl Vec { // zero-size types consume no memory, so we can't rely on the // address space running out self.len = self.len.checked_add(1).expect("length overflow"); - unsafe { mem::forget(value); } + mem::forget(value); return } @@ -994,7 +994,7 @@ impl Vec { num_u: 0, marker: PhantomData, }; - unsafe { mem::forget(vec); } + mem::forget(vec); while pv.num_t != 0 { unsafe { diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 101381e2c71..100b7e70591 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -232,10 +232,6 @@ extern "rust-intrinsic" { pub fn uninit() -> T; /// Moves a value out of scope without running drop glue. - /// - /// `forget` is unsafe because the caller is responsible for - /// ensuring the argument is deallocated already. - #[stable(feature = "rust1", since = "1.0.0")] pub fn forget(_: T) -> (); /// Unsafely transforms a value of one type into a value of another type. diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index c4128e79765..a149af3a440 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -22,15 +22,54 @@ use ptr; #[stable(feature = "rust1", since = "1.0.0")] pub use intrinsics::transmute; -/// Moves a thing into the void. +/// Leaks a value into the void, consuming ownership and never running its +/// destructor. /// -/// The forget function will take ownership of the provided value but neglect -/// to run any required cleanup or memory management operations on it. +/// This function will take ownership of its argument, but is distinct from the +/// `mem::drop` function in that it **does not run the destructor**, leaking the +/// value and any resources that it owns. /// -/// This function is the unsafe version of the `drop` function because it does -/// not run any destructors. +/// # Safety +/// +/// This function is not marked as `unsafe` as Rust does not guarantee that the +/// `Drop` implementation for a value will always run. Note, however, that +/// leaking resources such as memory or I/O objects is likely not desired, so +/// this function is only recommended for specialized use cases. +/// +/// The safety of this function implies that when writing `unsafe` code +/// yourself care must be taken when leveraging a destructor that is required to +/// run to preserve memory safety. There are known situations where the +/// destructor may not run (such as if ownership of the object with the +/// destructor is returned) which must be taken into account. +/// +/// # Other forms of Leakage +/// +/// It's important to point out that this function is not the only method by +/// which a value can be leaked in safe Rust code. Other known sources of +/// leakage are: +/// +/// * `Rc` and `Arc` cycles +/// * `mpsc::{Sender, Receiver}` cycles (they use `Arc` internally) +/// * Panicking destructors are likely to leak local resources +/// +/// # Example +/// +/// ```rust,no_run +/// use std::mem; +/// use std::fs::File; +/// +/// // Leak some heap memory by never deallocating it +/// let heap_memory = Box::new(3); +/// mem::forget(heap_memory); +/// +/// // Leak an I/O object, never closing the file +/// let file = File::open("foo.txt").unwrap(); +/// mem::forget(file); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] -pub use intrinsics::forget; +pub fn forget(t: T) { + unsafe { intrinsics::forget(t) } +} /// Returns the size of a type in bytes. /// diff --git a/src/libstd/sys/unix/fd.rs b/src/libstd/sys/unix/fd.rs index e5bdb554359..026380027d2 100644 --- a/src/libstd/sys/unix/fd.rs +++ b/src/libstd/sys/unix/fd.rs @@ -31,7 +31,7 @@ impl FileDesc { /// Extracts the actual filedescriptor without closing it. pub fn into_raw(self) -> c_int { let fd = self.fd; - unsafe { mem::forget(self) }; + mem::forget(self); fd } diff --git a/src/libstd/sys/windows/handle.rs b/src/libstd/sys/windows/handle.rs index 9481e180ce5..c835d503388 100644 --- a/src/libstd/sys/windows/handle.rs +++ b/src/libstd/sys/windows/handle.rs @@ -32,7 +32,7 @@ impl Handle { pub fn into_raw(self) -> HANDLE { let ret = self.0; - unsafe { mem::forget(self) } + mem::forget(self); return ret; }