Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update unsafe #218

Merged
merged 3 commits into from
Oct 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 5 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@ jobs:
- name: Add mdslides
run: |
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/ferrous-systems/mdslides/releases/download/v0.4.0/mdslides-installer.sh | sh


- name: Update Rust
run: |
rustup update stable

- name: Add Rust Targets
run: |
rustup target add thumbv7em-none-eabihf
Expand Down
67 changes: 47 additions & 20 deletions training-slides/src/unsafe.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,36 @@ For that reason, Rust has the concept of "unsafe code".

Unsafe code is allowed to:

- freely access memory
- dereference raw pointers
- call external functions
- declare values `Send` and `Sync`
- write to unsynced global variables
- freely access memory
- dereference raw pointers
- call external functions
- declare values `Send` and `Sync`
- write to unsynced global variables

---

By definition, these are not unsafe:

- conversion to raw pointers
- memory leaks
- conversion to raw pointers
- memory leaks

## Making pointers

```rust
#![allow(unused_variables)]
fn main() {
let mut x = 1;
// The old way
let p1 = &x as *const i32;
let p2 = &mut x as *mut i32;
// Added in 1.51, was unsafe until 1.82
let p1 = core::ptr::addr_of!(x);
let p2 = core::ptr::addr_of_mut!(x);
// As of Rust 1.82, use this instead:
let p1 = &raw const x;
let p2 = &raw mut x;
}
```

---

Expand All @@ -41,25 +59,34 @@ Safe Rust is the worst language to implement linked lists. There's a full [text
Unsafe code must *always* be marked `unsafe`.

```rust []
use std::fmt::Debug;

fn main() {
let pointer_to_int = &mut 1;
let raw = pointer_to_int as *mut i32;
unsafe { deref_pointer(raw) };
let mut x = 1;
let p = &raw mut x;
unsafe {
my_write(p, 100);
}
println!("x is {} (or {})", x, unsafe { p.read() });
}

unsafe fn deref_pointer<T: Debug>(p: *mut T) {
println!("{:?}", *p)
pub unsafe fn my_write<T>(p: *mut T, new_value: T) {
p.write(new_value)
}
```

Note:

Modern Rust generally tries to have only a small number of `unsafe` operations
per `unsafe` block. And any unsafe function *should* still use `unsafe` blocks for
the unsafe code within, even though the function itself is unsafe to call.

Try running `clippy` on this example and play with `clippy::multiple_unsafe_ops_per_block` and `clippy::undocumented_unsafe_blocks`. Then try "Edition 2024".

## Traps of `unsafe`

- Not all examples are that simple. `unsafe` *must* guarantee the invariants that Rust expects.
- This *especially* applies to ownership and mutable borrowing
- `unsafe` can lead to a value having 2 owners -&gt; double free
- `unsafe` can make immutable data temporarily mutable, which will lead to broken promises and tears.
- Not all examples are that simple. `unsafe` *must* guarantee the invariants that Rust expects.
- This *especially* applies to ownership and mutable borrowing
- `unsafe` can lead to a value having 2 owners -&gt; double free
- `unsafe` can make immutable data temporarily mutable, which will lead to broken promises and tears.

---

Expand All @@ -84,8 +111,8 @@ fn split_at_mut<T>(value: &mut [T], mid: usize) -> (&mut [T], &mut [T]) {

## Highlight unsafe code in VSCode

* Will highlight which function calls are `unsafe` inside an `unsafe` block
* Helpful for longer `unsafe` blocks
- Will highlight which function calls are `unsafe` inside an `unsafe` block
- Helpful for longer `unsafe` blocks

```json
{
Expand Down