google / google/comprehensive-rust

"Calling unsafe functions" example is confusing

Open
#2,733 0 comments 1 reaction 0 assignees View on GitHub
Dominant language
Rust
Stars
33.4k
Forks
2.1k
Avg merge
1d 3h
Merged PRs (30d)
10

Description

See the [code example](https://github.com/google/comprehensive-rust/blob/main/src/unsafe-rust/unsafe-functions/calling.md):
```rust
#[derive(Debug)]
#[repr(C)]
struct KeyPair {
pk: [u16; 4], // 8 bytes
sk: [u16; 4], // 8 bytes
}

const PK_BYTE_LEN: usize = 8;

fn log_public_key(pk_ptr: *const u16) {
let pk: &[u16] = unsafe { std::slice::from_raw_parts(pk_ptr, PK_BYTE_LEN) };
println!("{pk:?}");
}

fn main() {
let key_pair = KeyPair { pk: [1, 2, 3, 4], sk: [0, 0, 42, 0] };
log_public_key(key_pair.pk.as_ptr());
}
```

The sample shows a call to `std::slice::from_raw_parts` that does not fulfill that function's precondition; [namely](https://doc.rust-lang.org/stable/std/slice/fn.from_raw_parts.html):

> The `len` argument is the number of *elements*, not the number of bytes.

In this case, the size of `pk` in bytes (`PK_BYTES_LEN`) is passed in. But what's confusing is that `PK_BYTES_LEN` also happens to be the *combined length* (in elements) of the two adjacent `pk` and `sk` fields. Thus we end up discussing that even if two objects happen to be laid out contiguously in memory (which C may guarantee, but Rust does not), it's still UB to read off the end of one object into the data of another one (in both languages).

This means a digression into struct layouts in C and Rust as well as the C and Rust memory models' ideas of pointer provenance. These aren't bad things to discuss, but distract from the point of this slide, which is to describe the importance of fulfilling the contracts of unsafe functions.

I think we should remove `sk` and the `KeyPair` wrapper entirely and simply demonstrate a confused call to `std::slice::from_raw_parts`. Then we can just say that the UB ultimately comes from reading outside the bounds of the object without having to discuss additional topics.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.