diff options
| author | Cristi Cobzarenco <cristi.cobzarenco@gmail.com> | 2016-10-15 16:32:14 +0100 |
|---|---|---|
| committer | Cristi Cobzarenco <cristi.cobzarenco@gmail.com> | 2016-11-05 00:50:41 +0000 |
| commit | 651cf58f2e906fa6d333013891adca5074440bea (patch) | |
| tree | 0a9de6025b1d0605d854beb2cbfbda06fb91c4d2 /src/liballoc | |
| parent | d34318dd538bf4c9175e4138b3e4188ea8211620 (diff) | |
| download | rust-651cf58f2e906fa6d333013891adca5074440bea.tar.gz rust-651cf58f2e906fa6d333013891adca5074440bea.zip | |
Add `{into,from}_raw` to Rc and Arc
Diffstat (limited to 'src/liballoc')
| -rw-r--r-- | src/liballoc/arc.rs | 79 | ||||
| -rw-r--r-- | src/liballoc/lib.rs | 4 | ||||
| -rw-r--r-- | src/liballoc/macros.rs | 28 | ||||
| -rw-r--r-- | src/liballoc/rc.rs | 79 |
4 files changed, 190 insertions, 0 deletions
diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index 7a07e007ce1..5db5a315f4a 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -270,6 +270,68 @@ impl<T> Arc<T> { Ok(elem) } } + + /// Consumes the `Arc`, returning the wrapped pointer. + /// + /// To avoid a memory leak the pointer must be converted back to an `Arc` using + /// [`Arc::from_raw`][from_raw]. + /// + /// [from_raw]: struct.Arc.html#method.from_raw + /// + /// # Examples + /// + /// ``` + /// #![feature(rc_raw)] + /// + /// use std::sync::Arc; + /// + /// let x = Arc::new(10); + /// let x_ptr = Arc::into_raw(x); + /// assert_eq!(unsafe { *x_ptr }, 10); + /// ``` + #[unstable(feature = "rc_raw", issue = "37197")] + pub fn into_raw(this: Self) -> *mut T { + let ptr = unsafe { &mut (**this.ptr).data as *mut _ }; + mem::forget(this); + ptr + } + + /// Constructs an `Arc` from a raw pointer. + /// + /// The raw pointer must have been previously returned by a call to a + /// [`Arc::into_raw`][into_raw]. + /// + /// This function is unsafe because improper use may lead to memory problems. For example, a + /// double-free may occur if the function is called twice on the same raw pointer. + /// + /// [into_raw]: struct.Arc.html#method.into_raw + /// + /// # Examples + /// + /// ``` + /// #![feature(rc_raw)] + /// + /// use std::sync::Arc; + /// + /// let x = Arc::new(10); + /// let x_ptr = Arc::into_raw(x); + /// + /// unsafe { + /// // Convert back to an `Arc` to prevent leak. + /// let x = Arc::from_raw(x_ptr); + /// assert_eq!(*x, 10); + /// + /// // Further calls to `Arc::from_raw(x_ptr)` would be memory unsafe. + /// } + /// + /// // The memory was freed when `x` went out of scope above, so `x_ptr` is now dangling! + /// ``` + #[unstable(feature = "rc_raw", issue = "37197")] + pub unsafe fn from_raw(ptr: *mut T) -> Self { + // To find the corresponding pointer to the `ArcInner` we need to subtract the offset of the + // `data` field from the pointer. + Arc { ptr: Shared::new((ptr as *mut u8).offset(-offset_of!(ArcInner<T>, data)) as *mut _) } + } } impl<T: ?Sized> Arc<T> { @@ -1180,6 +1242,23 @@ mod tests { } #[test] + fn into_from_raw() { + let x = Arc::new(box "hello"); + let y = x.clone(); + + let x_ptr = Arc::into_raw(x); + drop(y); + unsafe { + assert_eq!(**x_ptr, "hello"); + + let x = Arc::from_raw(x_ptr); + assert_eq!(**x, "hello"); + + assert_eq!(Arc::try_unwrap(x).map(|x| *x), Ok("hello")); + } + } + + #[test] fn test_cowarc_clone_make_mut() { let mut cow0 = Arc::new(75); let mut cow1 = cow0.clone(); diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 31491106d97..0d450184ed8 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -99,6 +99,10 @@ #[macro_use] extern crate std; +// Module with internal macros used by other modules (needs to be included before other modules). +#[macro_use] +mod macros; + // Heaps provided for low-level allocation strategies pub mod heap; diff --git a/src/liballoc/macros.rs b/src/liballoc/macros.rs new file mode 100644 index 00000000000..7da91c87e96 --- /dev/null +++ b/src/liballoc/macros.rs @@ -0,0 +1,28 @@ +// Copyright 2013-2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Private macro to get the offset of a struct field in bytes from the address of the struct. +macro_rules! offset_of { + ($container:path, $field:ident) => {{ + // Make sure the field actually exists. This line ensures that a compile-time error is + // generated if $field is accessed through a Deref impl. + let $container { $field : _, .. }; + + // Create an (invalid) instance of the container and calculate the offset to its + // field. Using a null pointer might be UB if `&(*(0 as *const T)).field` is interpreted to + // be nullptr deref. + let invalid: $container = ::core::mem::uninitialized(); + let offset = &invalid.$field as *const _ as usize - &invalid as *const _ as usize; + + // Do not run destructors on the made up invalid instance. + ::core::mem::forget(invalid); + offset as isize + }}; +} diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 699f777138d..bd87abc720d 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -363,6 +363,68 @@ impl<T> Rc<T> { pub fn would_unwrap(this: &Self) -> bool { Rc::strong_count(&this) == 1 } + + /// Consumes the `Rc`, returning the wrapped pointer. + /// + /// To avoid a memory leak the pointer must be converted back to an `Rc` using + /// [`Rc::from_raw`][from_raw]. + /// + /// [from_raw]: struct.Rc.html#method.from_raw + /// + /// # Examples + /// + /// ``` + /// #![feature(rc_raw)] + /// + /// use std::rc::Rc; + /// + /// let x = Rc::new(10); + /// let x_ptr = Rc::into_raw(x); + /// assert_eq!(unsafe { *x_ptr }, 10); + /// ``` + #[unstable(feature = "rc_raw", issue = "37197")] + pub fn into_raw(this: Self) -> *mut T { + let ptr = unsafe { &mut (**this.ptr).value as *mut _ }; + mem::forget(this); + ptr + } + + /// Constructs an `Rc` from a raw pointer. + /// + /// The raw pointer must have been previously returned by a call to a + /// [`Rc::into_raw`][into_raw]. + /// + /// This function is unsafe because improper use may lead to memory problems. For example, a + /// double-free may occur if the function is called twice on the same raw pointer. + /// + /// [into_raw]: struct.Rc.html#method.into_raw + /// + /// # Examples + /// + /// ``` + /// #![feature(rc_raw)] + /// + /// use std::rc::Rc; + /// + /// let x = Rc::new(10); + /// let x_ptr = Rc::into_raw(x); + /// + /// unsafe { + /// // Convert back to an `Rc` to prevent leak. + /// let x = Rc::from_raw(x_ptr); + /// assert_eq!(*x, 10); + /// + /// // Further calls to `Rc::from_raw(x_ptr)` would be memory unsafe. + /// } + /// + /// // The memory was freed when `x` went out of scope above, so `x_ptr` is now dangling! + /// ``` + #[unstable(feature = "rc_raw", issue = "37197")] + pub unsafe fn from_raw(ptr: *mut T) -> Self { + // To find the corresponding pointer to the `RcBox` we need to subtract the offset of the + // `value` field from the pointer. + Rc { ptr: Shared::new((ptr as *mut u8).offset(-offset_of!(RcBox<T>, value)) as *mut _) } + } } impl<T: ?Sized> Rc<T> { @@ -1262,6 +1324,23 @@ mod tests { } #[test] + fn into_from_raw() { + let x = Rc::new(box "hello"); + let y = x.clone(); + + let x_ptr = Rc::into_raw(x); + drop(y); + unsafe { + assert_eq!(**x_ptr, "hello"); + + let x = Rc::from_raw(x_ptr); + assert_eq!(**x, "hello"); + + assert_eq!(Rc::try_unwrap(x).map(|x| *x), Ok("hello")); + } + } + + #[test] fn get_mut() { let mut x = Rc::new(3); *Rc::get_mut(&mut x).unwrap() = 4; |
