Skip to content

Commit 9860a4e

Browse files
authored
Rollup merge of rust-lang#62514 - stephaneyfx:box-ffi, r=nikomatsakis
Clarify `Box<T>` representation and its use in FFI This officializes what was only shown as a code example in [the unsafe code guidelines](https://rust-lang.github.io/unsafe-code-guidelines/layout/function-pointers.html?highlight=box#use) and follows [the discussion](rust-lang/unsafe-code-guidelines#157) in the corresponding repository. It is also related to [the issue](rust-lang#52976) regarding marking `Box<T>` `#[repr(transparent)]`. If the statement this PR adds is incorrect or a more in-depth discussion is warranted, I apologize. Should it be the case, the example in the unsafe code guidelines should be amended and some document should make it clear that it is not sound/supported.
2 parents 27d6f55 + fafa489 commit 9860a4e

File tree

1 file changed

+53
-0
lines changed

1 file changed

+53
-0
lines changed

src/liballoc/boxed.rs

+53
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,60 @@
6161
//! T` obtained from [`Box::<T>::into_raw`] may be deallocated using the
6262
//! [`Global`] allocator with [`Layout::for_value(&*value)`].
6363
//!
64+
//! So long as `T: Sized`, a `Box<T>` is guaranteed to be represented
65+
//! as a single pointer and is also ABI-compatible with C pointers
66+
//! (i.e. the C type `T*`). This means that if you have extern "C"
67+
//! Rust functions that will be called from C, you can define those
68+
//! Rust functions using `Box<T>` types, and use `T*` as corresponding
69+
//! type on the C side. As an example, consider this C header which
70+
//! declares functions that create and destroy some kind of `Foo`
71+
//! value:
6472
//!
73+
//! ```c
74+
//! /* C header */
75+
//!
76+
//! /* Returns ownership to the caller */
77+
//! struct Foo* foo_new(void);
78+
//!
79+
//! /* Takes ownership from the caller; no-op when invoked with NULL */
80+
//! void foo_delete(struct Foo*);
81+
//! ```
82+
//!
83+
//! These two functions might be implemented in Rust as follows. Here, the
84+
//! `struct Foo*` type from C is translated to `Box<Foo>`, which captures
85+
//! the ownership constraints. Note also that the nullable argument to
86+
//! `foo_delete` is represented in Rust as `Option<Box<Foo>>`, since `Box<Foo>`
87+
//! cannot be null.
88+
//!
89+
//! ```
90+
//! #[repr(C)]
91+
//! pub struct Foo;
92+
//!
93+
//! #[no_mangle]
94+
//! pub extern "C" fn foo_new() -> Box<Foo> {
95+
//! Box::new(Foo)
96+
//! }
97+
//!
98+
//! #[no_mangle]
99+
//! pub extern "C" fn foo_delete(_: Option<Box<Foo>>) {}
100+
//! ```
101+
//!
102+
//! Even though `Box<T>` has the same representation and C ABI as a C pointer,
103+
//! this does not mean that you can convert an arbitrary `T*` into a `Box<T>`
104+
//! and expect things to work. `Box<T>` values will always be fully aligned,
105+
//! non-null pointers. Moreover, the destructor for `Box<T>` will attempt to
106+
//! free the value with the global allocator. In general, the best practice
107+
//! is to only use `Box<T>` for pointers that originated from the global
108+
//! allocator.
109+
//!
110+
//! **Important.** At least at present, you should avoid using
111+
//! `Box<T>` types for functions that are defined in C but invoked
112+
//! from Rust. In those cases, you should directly mirror the C types
113+
//! as closely as possible. Using types like `Box<T>` where the C
114+
//! definition is just using `T*` can lead to undefined behavior, as
115+
//! described in [rust-lang/unsafe-code-guidelines#198][ucg#198].
116+
//!
117+
//! [ucg#198]: https://github.com/rust-lang/unsafe-code-guidelines/issues/198
65118
//! [dereferencing]: ../../std/ops/trait.Deref.html
66119
//! [`Box`]: struct.Box.html
67120
//! [`Box<T>`]: struct.Box.html

0 commit comments

Comments
 (0)