Skip to content

Commit

Permalink
Merge pull request #34 from RalfJung/readme
Browse files Browse the repository at this point in the history
update motivating example
  • Loading branch information
RalfJung authored May 19, 2024
2 parents 172c607 + bdbad39 commit fe7f590
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 13 deletions.
29 changes: 16 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,19 @@

`cargo careful` is a tool to run your Rust code extra carefully -- opting into a bunch of
nightly-only extra checks that help detect Undefined Behavior, and using a standard library with
debug assertions. For example, it will find the error in the following snippet:
debug assertions.
The standard library does check for some Undefined Behavior when the program is built
with debug assertions, but some of these checks are disabled because their performance
impact was considered too high.
For example, it will find the alignment issue in the following snippet:

```rust
fn main() {
let arr = [1, 2, 3, 4];
let slice = &arr[..2];
let value = unsafe { slice.get_unchecked(2) };
println!("The value is {}!", value);
let arr = [1u8, 2, 3, 4];
for n in [0, 1] {
let val = unsafe { arr.as_ptr().add(n).cast::<u16>().read() };
println!("The value is {val}!");
}
}
```

Expand All @@ -36,20 +41,18 @@ The first time you run `cargo careful`, it needs to run some setup steps, which

## What does it do?

### Assertions
### Detect Undefined Behavior

The most important thing `cargo careful` does is that it builds the standard library with debug
assertions. The standard library already contains quite a few sanity checks that are enabled as
debug assertions, but the usual rustup distribution compiles them all away to avoid run-time checks.
assertions.
The standard library does check for some Undefined Behavior when the program is built
with debug assertions, but some of these checks are disabled because their performance
impact was considered too high.
Furthermore, `cargo careful` sets some flags that tell rustc to insert extra run-time checks.

Here are some of the checks this enables:

- `get_unchecked` in slices performs bounds checks.
- `copy`, `copy_nonoverlapping`, and `write_bytes` check that pointers are aligned and non-null and
(if applicable) non-overlapping.
- `{NonNull,NonZero*,...}::new_unchecked` check that the value is valid.
- `unreachable_unchecked` checks that it actually is not being reached.
- `ptr.read()`/`ptr.write(v)` check that the pointer is aligned and non-null.
- The collection types perform plenty of internal consistency checks.
- `mem::zeroed` and the deprecated `mem::uninitialized` panic if the type does not allow that kind
of initialization (with a check that is stricter than the default). (This is `-Zstrict-init-checks`.)
Expand Down
12 changes: 12 additions & 0 deletions test/tests/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,18 @@ fn uninit_u8() {
let _ = unsafe { std::mem::uninitialized::<u8>() };
}

// We cannot test `read` alignment checks since that will abort, not unwind.
#[test]
#[ignore]
#[should_panic]
fn read_unaligned() {
let arr = [1u8, 2, 3, 4];
for n in [0, 1] {
let val = unsafe { arr.as_ptr().add(n).cast::<u16>().read() };
println!("The value is {val}!");
}
}

#[test]
#[should_panic]
fn c_str() {
Expand Down

0 comments on commit fe7f590

Please sign in to comment.