Skip to content

Commit

Permalink
Auto merge of #21318 - stepancheg:box-fns, r=alexcrichton
Browse files Browse the repository at this point in the history
Functions are needed for safety and convenience.

It is a common pattern to use `mem::transmute` to convert between
`Box` and raw pointer, like this:

```
let b = Box::new(3);
let p = mem::transmute(b);
// pass `p` to some C library
```

After this commit, conversion can be written as:

```
let p = b.into_raw();
```

`into_raw` and `from_raw` functions are still unsafe, but they are
much safer than `mem::transmute`, because *raw functions do not
convert between incompatible pointers. For example, this likely
incorrect code can be successfully compiled:

```
let p: *mut u64 = ...
let b: Box<u32> = mem::transmute(p);
```

Using `from_raw` results in compile-time error:

```
let p: *mut u64 = ...
let b: Box<u32> = Box::from_raw(p); // compile-time error
```

`into_raw` and `from_raw` functions are similar to C++ `std::unique_ptr`
`release` function [1] and constructor from pointer [2].

[1] http://en.cppreference.com/w/cpp/memory/unique_ptr/release
[2] http://en.cppreference.com/w/cpp/memory/unique_ptr/unique_ptr
  • Loading branch information
bors committed Feb 1, 2015
2 parents c2bda2a + 5a722f8 commit ca4b967
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 0 deletions.
46 changes: 46 additions & 0 deletions src/liballoc/boxed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,52 @@ impl<T> Box<T> {
}
}

impl<T : ?Sized> Box<T> {
/// Constructs a box from the raw pointer.
///
/// After this function call, pointer is owned by resulting box.
/// In particular, it means that `Box` destructor calls destructor
/// of `T` and releases memory. Since the way `Box` allocates and
/// releases memory is unspecified, so the only valid pointer to
/// pass to this function is the one taken from another `Box` with
/// `box::into_raw` function.
///
/// Function is unsafe, because improper use of this function may
/// lead to memory problems like double-free, for example if the
/// function is called twice on the same raw pointer.
#[unstable(feature = "alloc",
reason = "may be renamed or moved out of Box scope")]
pub unsafe fn from_raw(raw: *mut T) -> Self {
mem::transmute(raw)
}
}

/// Consumes the `Box`, returning the wrapped raw pointer.
///
/// After call to this function, caller is responsible for the memory
/// previously managed by `Box`, in particular caller should properly
/// destroy `T` and release memory. The proper way to do it is to
/// convert pointer back to `Box` with `Box::from_raw` function, because
/// `Box` does not specify, how memory is allocated.
///
/// Function is unsafe, because result of this function is no longer
/// automatically managed that may lead to memory or other resource
/// leak.
///
/// # Example
/// ```
/// use std::boxed;
///
/// let seventeen = Box::new(17u32);
/// let raw = unsafe { boxed::into_raw(seventeen) };
/// let boxed_again = unsafe { Box::from_raw(raw) };
/// ```
#[unstable(feature = "alloc",
reason = "may be renamed")]
pub unsafe fn into_raw<T : ?Sized>(b: Box<T>) -> *mut T {
mem::transmute(b)
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Default> Default for Box<T> {
#[stable(feature = "rust1", since = "1.0.0")]
Expand Down
42 changes: 42 additions & 0 deletions src/liballoc/boxed_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use core::ops::Deref;
use core::result::Result::{Ok, Err};
use core::clone::Clone;

use std::boxed;
use std::boxed::Box;
use std::boxed::BoxAny;

Expand Down Expand Up @@ -73,3 +74,44 @@ fn deref() {
fn homura<T: Deref<Target=i32>>(_: T) { }
homura(Box::new(765i32));
}

#[test]
fn raw_sized() {
unsafe {
let x = Box::new(17i32);
let p = boxed::into_raw(x);
assert_eq!(17, *p);
*p = 19;
let y = Box::from_raw(p);
assert_eq!(19, *y);
}
}

#[test]
fn raw_trait() {
trait Foo {
fn get(&self) -> u32;
fn set(&mut self, value: u32);
}

struct Bar(u32);

impl Foo for Bar {
fn get(&self) -> u32 {
self.0
}

fn set(&mut self, value: u32) {
self.0 = value;
}
}

unsafe {
let x: Box<Foo> = Box::new(Bar(17));
let p = boxed::into_raw(x);
assert_eq!(17, (*p).get());
(*p).set(19);
let y: Box<Foo> = Box::from_raw(p);
assert_eq!(19, y.get());
}
}

0 comments on commit ca4b967

Please sign in to comment.