Skip to content

Commit 1d037c0

Browse files
committedNov 17, 2023
doc: document handling of dynamically sized types
1 parent e5e09a0 commit 1d037c0

File tree

1 file changed

+48
-0
lines changed

1 file changed

+48
-0
lines changed
 

‎CONTRIBUTING.md

+48
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,51 @@ If you're making changes to rustls-ffi, you'll need
2626
regenerate the header file:
2727

2828
make src/rustls.h
29+
30+
## Dynamically Sized Types
31+
32+
Many types exposed in this API are wrapped in a `Box` or an `Arc`, which can be
33+
straightforwardly turned into a raw pointer and shared with C using `into_raw`.
34+
35+
However, Rust has a category of [Dynamically Sized Types] (DSTs), which in particular
36+
includes [trait objects] (i.e. `dyn Foo`). DSTs must always be wrapped in a
37+
pointer type, e.g. `Box`, `Arc`, `&`, `&mut`, `*mut`, or `*const`. When a pointer
38+
type wraps a DST it's colloquially called a "fat pointer" because it's twice the
39+
size of a pointer to a sized type. In the case of trait objects, the extra data
40+
is a pointer to the vtable.
41+
42+
Even though Rust supports raw, fat pointers, they are not FFI-safe. Consider
43+
this example:
44+
45+
```rust
46+
extern "C" fn foo(_: *const dyn ToString) { }
47+
```
48+
49+
```
50+
warning: `extern` fn uses type `dyn ToString`, which is not FFI-safe
51+
--> foo.rs:1:22
52+
|
53+
1 | extern "C" fn foo(_: *const dyn ToString) { }
54+
| ^^^^^^^^^^^^^^^^^^^ not FFI-safe
55+
|
56+
= note: trait objects have no C equivalent
57+
= note: `#[warn(improper_ctypes_definitions)]` on by default
58+
```
59+
60+
That makes sense: in the C ABI, all pointers are the same size. There is no
61+
concept of a fat pointer.
62+
63+
Since the Rustls API includes some use of trait objects, we need a way to
64+
represent them in the C ABI. We do that by creating two pointers: an outer,
65+
thin pointer (usually a `Box`), and an inner, fat pointer (usually an `Arc`).
66+
For instance:
67+
68+
```rust
69+
Box<Arc<dyn ServerCertVerifier>>
70+
```
71+
72+
This allows us to convert the outer pointer with `into_raw()` and pass it back
73+
and forth across the FFI boundary.
74+
75+
[Dynamically Sized Types]: https://doc.rust-lang.org/beta/reference/dynamically-sized-types.html
76+
[trait objects]: https://doc.rust-lang.org/beta/reference/types/trait-object.html

0 commit comments

Comments
 (0)
Please sign in to comment.