Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
4f5f4c0
Pinning initial draft
timClicks Dec 15, 2025
b26359d
minor: punctuation
timClicks Dec 15, 2025
2fb9663
Add more pinning content
timClicks Dec 16, 2025
6eaca2a
Add Pinning chapter to Deep Dive Course
timClicks Dec 16, 2025
5212c40
Checking in progress
timClicks Dec 17, 2025
ce33cb3
chore: Promote unsafe case studies to the top level
timClicks Dec 18, 2025
9cf0969
More pinning content
timClicks Dec 18, 2025
ee015af
Update welcome slide
timClicks Dec 18, 2025
2def9e5
Add introduction segment
timClicks Dec 18, 2025
1156ce6
Refactor characteristics into sub-section
timClicks Dec 18, 2025
d9e0028
Bring SUMMARY.md up-to-date
timClicks Dec 18, 2025
63f95b9
Remove segment outline from inner
timClicks Dec 18, 2025
3d7c260
Add round of intros to welcome
timClicks Dec 18, 2025
62d5a35
Expand intro
timClicks Dec 18, 2025
c857e79
Safety preconditions section
timClicks Dec 19, 2025
c549c36
Update Introduction section
timClicks Dec 19, 2025
34c4c70
Move details to details
timClicks Dec 19, 2025
911fd2c
Add determining preconditions content
timClicks Dec 19, 2025
fb631d2
Add Rules of the Game content
timClicks Dec 19, 2025
ef3b4f0
minor fixes
timClicks Dec 19, 2025
97e0964
Add initial memory lifecycle content
timClicks Dec 19, 2025
a639dff
Update top-level slides
timClicks Dec 19, 2025
b1d2daa
Add more content
timClicks Dec 19, 2025
9ac94db
Remove stale content
timClicks Dec 19, 2025
5cc2bb3
Add references example to safety preconditions
timClicks Dec 19, 2025
c60d715
Add FFI content
timClicks Dec 19, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 75 additions & 10 deletions src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -486,16 +486,81 @@

- [Welcome](unsafe-deep-dive/welcome.md)
- [Setup](unsafe-deep-dive/setup.md)
- [Motivations](unsafe-deep-dive/motivations.md)
- [Interoperability](unsafe-deep-dive/motivations/interop.md)
- [Data Structures](unsafe-deep-dive/motivations/data-structures.md)
- [Performance](unsafe-deep-dive/motivations/performance.md)
- [Foundations](unsafe-deep-dive/foundations.md)
- [What is unsafe?](unsafe-deep-dive/foundations/what-is-unsafe.md)
- [When is unsafe used?](unsafe-deep-dive/foundations/when-is-unsafe-used.md)
- [Data structures are safe](unsafe-deep-dive/foundations/data-structures-are-safe.md)
- [Actions might not be](unsafe-deep-dive/foundations/actions-might-not-be.md)
- [Less powerful than it seems](unsafe-deep-dive/foundations/less-powerful.md)
- [Introduction](unsafe-deep-dive/introduction.md)
- [Defining Unsafe Rust](unsafe-deep-dive/introduction/definition.md)
- [Purpose of the unsafe keyword](unsafe-deep-dive/introduction/purpose.md)
- [Two roles of the unsafe keyword](unsafe-deep-dive/introduction/two-roles.md)
- [Warm Up Examples](unsafe-deep-dive/introduction/warm-up.md)
- [Using an unsafe block](unsafe-deep-dive/introduction/warm-up/unsafe-block.md)
- [Defining an unsafe function](unsafe-deep-dive/introduction/warm-up/unsafe-fn.md)
- [Implementing an unsafe trait](unsafe-deep-dive/introduction/warm-up/unsafe-impl.md)
- [Defining an unsafe trait](unsafe-deep-dive/introduction/warm-up/unsafe-trait.md)
- [Characteristics of Unsafe Rust](unsafe-deep-dive/introduction/characteristics-of-unsafe-rust.md)
- [Dangerous](unsafe-deep-dive/introduction/characteristics-of-unsafe-rust/dangerous.md)
- [Sometimes necessary](unsafe-deep-dive/introduction/characteristics-of-unsafe-rust/sometimes-necessary.md)
- [Sometimes useful](unsafe-deep-dive/introduction/characteristics-of-unsafe-rust/sometimes-useful.md)
- [Responsibility shift](unsafe-deep-dive/introduction/responsibility-shift.md)
- [Stronger development workflow required](unsafe-deep-dive/introduction/impact-on-workflow.md)
- [Example: may_overflow](unsafe-deep-dive/introduction/may_overflow.md)
- [Safety Preconditions](unsafe-deep-dive/safety-preconditions.md)
- [Common Preconditions](unsafe-deep-dive/safety-preconditions/common-preconditions.md)
- [Getter example](unsafe-deep-dive/safety-preconditions/getter.md)
- [Semantic preconditions](unsafe-deep-dive/safety-preconditions/semantic-preconditions.md)
- [Example: u8 to bool](unsafe-deep-dive/safety-preconditions/u8-to-bool.md)
- [Determining preconditions](unsafe-deep-dive/safety-preconditions/determining.md)
- [Example: references](unsafe-deep-dive/safety-preconditions/references.md)
- [Defining your own preconditions](unsafe-deep-dive/safety-preconditions/defining.md)
- [Example: ASCII Type](unsafe-deep-dive/safety-preconditions/ascii.md)
- [Rules of the game](unsafe-deep-dive/rules-of-the-game.md)
- [Rust is sound](unsafe-deep-dive/rules-of-the-game/rust-is-sound.md)
- [Copying memory](unsafe-deep-dive/rules-of-the-game/copying-memory.md)
- [Safe Rust](unsafe-deep-dive/rules-of-the-game/copying-memory/safe.md)
- [Encapsulated Unsafe Rust](unsafe-deep-dive/rules-of-the-game/copying-memory/encapsulated-unsafe.md)
- [Exposed Unsafe Rust](unsafe-deep-dive/rules-of-the-game/copying-memory/exposed-unsafe.md)
- [Documented safety preconditions](unsafe-deep-dive/rules-of-the-game/copying-memory/documented-safety-preconditions.md)
- [Crying Wolf](unsafe-deep-dive/rules-of-the-game/copying-memory/crying-wolf.md)
- [3 shapes of sound Rust](unsafe-deep-dive/rules-of-the-game/3-shapes-of-sound-rust.md)
- [Soundness Proof](unsafe-deep-dive/rules-of-the-game/soundness-proof.md)
- [Soundness](unsafe-deep-dive/rules-of-the-game/soundness-proof/soundness.md)
- [Corollary](unsafe-deep-dive/rules-of-the-game/soundness-proof/corollary.md)
- [Unsoundness](unsafe-deep-dive/rules-of-the-game/soundness-proof/unsoundness.md)
- [Memory Lifecycle](unsafe-deep-dive/memory-lifecycle.md)
- [Initialization](unsafe-deep-dive/initialization.md)
- [MaybeUninit<T>](unsafe-deep-dive/initialization/maybeuninit.md)
- [Arrays of uninit](unsafe-deep-dive/initialization/maybeuninit/arrays.md)
- [MaybeUninit::zeroed()](unsafe-deep-dive/initialization/maybeuninit/zeroed-method.md)
- [ptr::write vs assignment](unsafe-deep-dive/initialization/maybeuninit/write-vs-assignment.md)
- [How to initialize memory](unsafe-deep-dive/initialization/how-to-initialize-memory.md)
- [Partial initialization](unsafe-deep-dive/initialization/partial-initialization.md)
- [Pinning](unsafe-deep-dive/pinning.md)
- [What pinning is](unsafe-deep-dive/pinning/what-pinning-is.md)
- [What a move is](unsafe-deep-dive/pinning/what-a-move-is.md)
- [Definition of Pin<Ptr>](unsafe-deep-dive/pinning/definition-of-pin.md)
- [Why it's difficult](unsafe-deep-dive/pinning/why-difficult.md)
- [`Unpin` trait](unsafe-deep-dive/pinning/unpin-trait.md)
- [`PhantomPinned`](unsafe-deep-dive/pinning/phantompinned.md)
- [Self-Referential Buffer Example](unsafe-deep-dive/pinning/self-referential-buffer.md)
- [C++ implementation](unsafe-deep-dive/pinning/self-referential-buffer/cpp.md)
- [Modeled in Rust](unsafe-deep-dive/pinning/self-referential-buffer/rust.md)
- [With a raw pointer](unsafe-deep-dive/pinning/self-referential-buffer/rust-raw-pointers.md)
- [With an integer offset](unsafe-deep-dive/pinning/self-referential-buffer/rust-offset.md)
- [With `Pin<Ptr>`](unsafe-deep-dive/pinning/self-referential-buffer/rust-pin.md)
- [`Pin<Ptr>` and `Drop`](unsafe-deep-dive/pinning/pin-and-drop.md)
- [Worked Example](unsafe-deep-dive/pinning/drop-and-not-unpin-worked-example.md)
- [FFI](unsafe-deep-dive/ffi.md)
- [Language Interop](unsafe-deep-dive/ffi/language-interop.md)
- [Strategies](unsafe-deep-dive/ffi/strategies.md)
- [Consideration: Type Safety](unsafe-deep-dive/ffi/type-safety.md)
- [Language differences](unsafe-deep-dive/ffi/language-differences.md)
- [Different representations](unsafe-deep-dive/ffi/language-differences/representations.md)
- [Different semantics](unsafe-deep-dive/ffi/language-differences/semantics.md)
- [Rust ↔ C](unsafe-deep-dive/ffi/language-differences/rust-and-c.md)
- [C++ ↔ C](unsafe-deep-dive/ffi/language-differences/cpp-and-c.md)
- [Rust ↔ C++](unsafe-deep-dive/ffi/language-differences/rust-and-cpp.md)
- [`abs(3)`](unsafe-deep-dive/ffi/abs.md)
- [`rand(3)`](unsafe-deep-dive/ffi/rand.md)
- [Exercise:C library](unsafe-deep-dive/ffi/c-library-example.md)
- [Exercise: C++ library](unsafe-deep-dive/ffi/cpp-library-example.md)

---

Expand Down
9 changes: 9 additions & 0 deletions src/unsafe-deep-dive/case-studies.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Case Studies

Uses of `unsafe` in production that may be useful for further study:

| Case study | Topics |
| ------------------------------- | -------------------------------------- |
| tokio's [Intrusive Linked List] | UnsafeCell, PhantomData, PhantomPinned |

[Intrusive Linked List]: case-studies/intrusive-linked-list.md
106 changes: 106 additions & 0 deletions src/unsafe-deep-dive/case-studies/intrusive-linked-list.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
# Tokio's Intrusive Linked List

> Current as of tokio v1.48.0

The Tokio project maintains an [intrusive linked list implementation][ill] that
demonstrates many use cases of `unsafe` and a number of types and traits from
Rust's unsafe ecosystem, including `cell::UnsafeCell`, `mem::ManuallyDrop`,
[pinning](../pinning/what-pinning-is.md), and unsafe traits.

A linked list is a difficult data structure to implement in Rust, because it
relies heavily on stable memory addresses remaining stable. This isn't something
that happens naturally, as Rust types change their memory address every time
they move.

## Introductory Walkthrough

The public API is provided by the `LinkedList<L, T>` type, which contains fields
for the start and the end of the list. `Option<NonNull<T>>` could be read as a
`Option<*mut T>`, with the assurance that null pointers will never be created.

`NonNull<T>` is "_covariant_ over `T`", which means that `NonNull<T>` inherits
the [variance] relationships from `T`.

```rust,ignore
use core::marker::PhantomData;

// ...

/// An intrusive linked list.
///
/// Currently, the list is not emptied on drop. It is the caller's
/// responsibility to ensure the list is empty before dropping it.
pub(crate) struct LinkedList<L, T> {
/// Linked list head
head: Option<NonNull<T>>,

/// Linked list tail
tail: Option<NonNull<T>>,

/// Node type marker.
_marker: PhantomData<*const L>,
}
```

`LinkedList` is neither `Send` nor `Sync`, unless its targets are.

```rust,ignore
unsafe impl<L: Link> Send for LinkedList<L, L::Target> where L::Target: Send {}
unsafe impl<L: Link> Sync for LinkedList<L, L::Target> where L::Target: Sync {}
```

The `Link` trait used the those trait bounds is defined next. `Link` is an
unsafe trait that manages the relationships between nodes when the list needs to
pass references externally to callers.

Here's trait's definition. The most significant method is `pointers()`, which
returns a `Pointers` struct. `Pointers` provides access to the two ends of the
link by marking itself as `!Unpin`.

```rust,ignore
pub unsafe trait Link {
type Handle;

type Target;

fn as_raw(handle: &Self::Handle) -> NonNull<Self::Target>;

unsafe fn from_raw(ptr: NonNull<Self::Target>) -> Self::Handle;

/// # Safety
///
/// The resulting pointer should have the same tag in the stacked-borrows
/// stack as the argument. In particular, the method may not create an
/// intermediate reference in the process of creating the resulting raw
/// pointer.
unsafe fn pointers(
target: NonNull<Self::Target>,
) -> NonNull<Pointers<Self::Target>>;
}
```

`Pointers` is where the magic happens:

```rust,ignore
pub(crate) struct Pointers<T> {
inner: UnsafeCell<PointersInner<T>>,
}

struct PointersInner<T> {
prev: Option<NonNull<T>>,
next: Option<NonNull<T>>,

/// This type is !Unpin due to the heuristic from:
/// <https://github.com/rust-lang/rust/pull/82834>
_pin: PhantomPinned,
}
```

## Remarks

Understanding the whole implementation will take some time, but it's a rewarding
experience. The code demonstrates composing many parts of unsafe Rust's
ecosystem into a workable, high performance data structure. Enjoy exploring!

[ill]: https://docs.rs/tokio/1.48.0/src/tokio/util/linked_list.rs.html
[variance]: https://doc.rust-lang.org/reference/subtyping.html
1 change: 1 addition & 0 deletions src/unsafe-deep-dive/ffi.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# FFI
7 changes: 7 additions & 0 deletions src/unsafe-deep-dive/ffi/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
This segment of the class is about the foreign function interface with Rust.

outline:

Start by wrapping a simple C function

progress into more complex cases which involve pointers and uninitialized memory
111 changes: 111 additions & 0 deletions src/unsafe-deep-dive/ffi/abs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
---
minutes: 15
---

# Wrapping `abs(3)`

```rust,editable
fn abs(x: i32) -> i32;

fn main() {
let x = -42;
let abs_x = abs(x);
println!("{x}, {abs_x}");
}
```

<details>

In this slide, we’re establishing a pattern for writing wrappers.

Find the external definition of a function’s signature Write a matching function
in Rust within an `extern` block Confirm which safety invariants need to be
upheld Decide whether it’s possible to mark the function as safe

Note that this doesn’t work _yet_.

Add the extern block:

```rust
extern "C" {
abs(x: i32) -> i32;
}
```

Explain that many POSIX functions are available Rust because cargo links against
the C standard library (libc) by default, which makes its symbols into the
program’s scope.

Show `man 3 abs` in the terminal or [a webpage][abs].

Explain that our function signature must match its definition:
`int abs(int j);`.

Update the code block to use the C types.

```rust
use std::ffi::c_int;

extern "C" {
abs(x: c_int) -> c_int;
}
```

Discuss rationale: using `ffi::c_int` increases the portability of our code.
When the standard library is compiled for the target platform, the platform can
determine the widths. According to the C standard, an `c_int` may be defined as
an `i16` rather than the much more common `i32`.

(Optional) Show the [documentation for c_int][c_int] to reveal that it is a type
alias for `i32`.

Attempt to compile to trigger “error: extern blocks must be unsafe” error
message.

Add the unsafe keyword to the block:

```rust
use std::ffi::c_int;

unsafe extern "C" {
fn abs(x: c_int) -> c_int;
}
```

Check that learners understand the significance of this change. We are required
to uphold type safety and other safety preconditions.

Re-compile

Add safe keyword to the abs function:

```rust
use std::ffi::c_int;

unsafe extern "C" {
safe fn abs(x: c_int) -> c_int;
}
```

Explain the `safe fn` marks `abs` as safe to call without an `unsafe` block.

Completed program for reference:

```rust
use std::ffi::c_int;

unsafe extern "C" {
safe fn abs(x: c_int) -> c_int;
}

fn main() {
let x = -42;
let abs_x = abs(x);
println!("{x}, {abs_x}");
}
```

[abs]: https://www.man7.org/linux/man-pages/man3/abs.3.html
[c_int]: https://doc.rust-lang.org/std/ffi/type.c_int.html

</details>
Loading
Loading