mirror of
https://github.com/google/comprehensive-rust.git
synced 2025-04-23 08:07:38 +02:00
101 lines
2.7 KiB
Markdown
101 lines
2.7 KiB
Markdown
---
|
|
minutes: 5
|
|
---
|
|
|
|
# Unsafe Functions
|
|
|
|
## Calling Unsafe Functions
|
|
|
|
A function or method can be marked `unsafe` if it has extra preconditions you
|
|
must uphold to avoid undefined behaviour:
|
|
|
|
```rust,editable
|
|
extern "C" {
|
|
fn abs(input: i32) -> i32;
|
|
}
|
|
|
|
fn main() {
|
|
let emojis = "🗻∈🌏";
|
|
|
|
// SAFETY: The indices are in the correct order, within the bounds of the
|
|
// string slice, and lie on UTF-8 sequence boundaries.
|
|
unsafe {
|
|
println!("emoji: {}", emojis.get_unchecked(0..4));
|
|
println!("emoji: {}", emojis.get_unchecked(4..7));
|
|
println!("emoji: {}", emojis.get_unchecked(7..11));
|
|
}
|
|
|
|
println!("char count: {}", count_chars(unsafe { emojis.get_unchecked(0..7) }));
|
|
|
|
// SAFETY: `abs` doesn't deal with pointers and doesn't have any safety
|
|
// requirements.
|
|
unsafe {
|
|
println!("Absolute value of -3 according to C: {}", abs(-3));
|
|
}
|
|
|
|
// Not upholding the UTF-8 encoding requirement breaks memory safety!
|
|
// println!("emoji: {}", unsafe { emojis.get_unchecked(0..3) });
|
|
// println!("char count: {}", count_chars(unsafe {
|
|
// emojis.get_unchecked(0..3) }));
|
|
}
|
|
|
|
fn count_chars(s: &str) -> usize {
|
|
s.chars().count()
|
|
}
|
|
```
|
|
|
|
## Writing Unsafe Functions
|
|
|
|
You can mark your own functions as `unsafe` if they require particular
|
|
conditions to avoid undefined behaviour.
|
|
|
|
```rust,editable
|
|
/// Swaps the values pointed to by the given pointers.
|
|
///
|
|
/// # Safety
|
|
///
|
|
/// The pointers must be valid and properly aligned.
|
|
unsafe fn swap(a: *mut u8, b: *mut u8) {
|
|
let temp = *a;
|
|
*a = *b;
|
|
*b = temp;
|
|
}
|
|
|
|
fn main() {
|
|
let mut a = 42;
|
|
let mut b = 66;
|
|
|
|
// SAFETY: ...
|
|
unsafe {
|
|
swap(&mut a, &mut b);
|
|
}
|
|
|
|
println!("a = {}, b = {}", a, b);
|
|
}
|
|
```
|
|
|
|
<details>
|
|
|
|
## Calling Unsafe Functions
|
|
|
|
`get_unchecked`, like most `_unchecked` functions, is unsafe, because it can
|
|
create UB if the range is incorrect. `abs` is unsafe for a different reason: it
|
|
is an external function (FFI). Calling external functions is usually only a
|
|
problem when those functions do things with pointers which might violate Rust's
|
|
memory model, but in general any C function might have undefined behaviour under
|
|
any arbitrary circumstances.
|
|
|
|
The `"C"` in this example is the ABI;
|
|
[other ABIs are available too](https://doc.rust-lang.org/reference/items/external-blocks.html).
|
|
|
|
## Writing Unsafe Functions
|
|
|
|
We wouldn't actually use pointers for a `swap` function - it can be done safely
|
|
with references.
|
|
|
|
Note that unsafe code is allowed within an unsafe function without an `unsafe`
|
|
block. We can prohibit this with `#[deny(unsafe_op_in_unsafe_fn)]`. Try adding
|
|
it and see what happens. This will likely change in a future Rust edition.
|
|
|
|
</details>
|