From 5a722f8632eabfa5a776171ebdd6c1f6385098c7 Mon Sep 17 00:00:00 2001 From: Stepan Koltsov Date: Sun, 1 Feb 2015 20:15:44 +0300 Subject: [PATCH] box: into_raw, from_raw functions 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 = boxed::into_raw(b); ``` `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 = mem::transmute(p); ``` Using `from_raw` results in compile-time error: ``` let p: *mut u64 = ... let b: Box = 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 --- src/liballoc/boxed.rs | 46 ++++++++++++++++++++++++++++++++++++++ src/liballoc/boxed_test.rs | 42 ++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+) diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 91577e30d9a01..504b58d8ad105 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -102,6 +102,52 @@ impl Box { } } +impl Box { + /// 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(b: Box) -> *mut T { + mem::transmute(b) +} + #[stable(feature = "rust1", since = "1.0.0")] impl Default for Box { #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/liballoc/boxed_test.rs b/src/liballoc/boxed_test.rs index 4ffb94e7a6106..f7ddfcb09d7fb 100644 --- a/src/liballoc/boxed_test.rs +++ b/src/liballoc/boxed_test.rs @@ -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; @@ -73,3 +74,44 @@ fn deref() { fn homura>(_: 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 = Box::new(Bar(17)); + let p = boxed::into_raw(x); + assert_eq!(17, (*p).get()); + (*p).set(19); + let y: Box = Box::from_raw(p); + assert_eq!(19, y.get()); + } +}