You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
* Incorrect state synchronization (non-blocking bugs)
53
-
* Resource leaks
54
-
* Pointer exposures
55
-
* Arithmetic errors
56
-
* Nondeterminism
52
+
* Incorrect state synchronization (non-blocking bugs)
53
+
* Resource leaks
54
+
* Pointer exposures
55
+
* Arithmetic errors
56
+
* Nondeterminism
57
57
* Logic errors
58
58
59
59
Moreover, safe Rust may happen to be unsound in some rare cases. Check [the issues on the Rust GitHub](https://github.com/rust-lang/rust/issues?q=is%3Aissue%20state%3Aopen%20label%3AI-unsound) and the ["Counterexamples in Type Systems"](https://counterexamples.org/intro.html) resource for more information. Usually auditors don’t need to focus on these edge cases.
@@ -76,8 +76,8 @@ Pointer exposure is considered safe, because it does not make your program explo
76
76
77
77
Dealing with numbers is safe in Rust, but some operations may produce unexpected results. There are three main sources of bugs:
There are [three types of integer bugs](https://phrack.org/issues/60/10.html#article): arithmetic overflows, width overflows, and signedness errors.
@@ -100,7 +100,7 @@ You can read more about integer overflows in [RFC 560](https://github.com/rust-l
100
100
101
101
Width and signedness overflows can occur when converting between numeric types. Thanks to Rust’s lack of implicit conversions, unexpected overflows are easy to deal with, using one of the following:
102
102
103
-
* A [checked conversion](https://doc.rust-lang.org/std/convert/trait.TryFrom.html) with overflows handled explicitly (e.g., with a panic)
103
+
* A [checked conversion](https://doc.rust-lang.org/std/convert/trait.TryFrom.html) with overflows handled explicitly (e.g., with a panic)
104
104
* An [`as` cast](https://doc.rust-lang.org/rust-by-example/types/cast.html) that may result in a wrap-over (but is always well defined, [unlike in C](https://stackoverflow.com/questions/16188263/is-signed-integer-overflow-still-undefined-behavior-in-c))
105
105
106
106
The latter cast method is more error-prone and should get the same amount of scrutiny as arithmetic overflows. An [`as` cast](https://doc.rust-lang.org/rust-by-example/types/cast.html) silently truncates bigger integer types converted to smaller integer types, even in debug mode.
@@ -113,16 +113,16 @@ There are two types of nondeterminism in Rust: introduced during compilation and
113
113
114
114
The following are sources of compilation-time nondeterminism:
115
115
116
-
* Architecture-dependent integral types (like `usize` and `libc::c_char`) and pointer sizes
Copy file name to clipboardExpand all lines: content/docs/languages/rust/20-dynamic-analysis.md
+37-35Lines changed: 37 additions & 35 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -244,13 +244,15 @@ To find deep bugs, we can run tests with [various sanitizers](https://doc.rust-l
244
244
245
245
Examples of Rust sanitizers commonly used for security testing include:
246
246
247
-
* AddressSanitizer
248
-
* HWAddressSanitizer
249
-
* LeakSanitizer
250
-
* MemorySanitizer
247
+
* AddressSanitizer
248
+
* HWAddressSanitizer
249
+
* LeakSanitizer
250
+
* MemorySanitizer
251
251
* ThreadSanitizer
252
252
253
-
To enable them, add the `RUSTFLAGS` environment variable.
253
+
To enable them, set the `RUSTFLAGS` environment variable.
254
+
255
+
The examples below run the subset supported by the shown `x86_64-unknown-linux-gnu` target. Sanitizers are target-specific, so adjust the sanitizer name and target triple for others like HWAddressSanitizer.
254
256
255
257
{{< hint warning >}}
256
258
At this time, nightly toolchains must be used for sanitizers. If you use the stable toolchain, the compilation fails with the following error:
@@ -334,13 +336,13 @@ mod tests {
334
336
335
337
## Miri
336
338
337
-
[Miri](https://github.com/rust-lang/miri) is an interpreter for Rust’s "mid-level intermediate representation." Miri helps to detect undefined behaviors like these:
339
+
[Miri](https://github.com/rust-lang/miri) is an interpreter for Rust’s "mid-level intermediate representation." Miri helps detect undefined behavior and related issues like these:
338
340
339
-
* Memory corruption bugs
340
-
* Memory leaks
341
-
* Uses of uninitialized data
342
-
* Memory alignment issues
343
-
* Issues with aliasing
341
+
* Memory corruption bugs
342
+
* Memory leaks
343
+
* Uses of uninitialized data
344
+
* Memory alignment issues
345
+
* Issues with aliasing
344
346
* Data races
345
347
346
348
To use Miri, you must point it at some executable code (it performs dynamic analysis). The easiest is to run your tests through Miri. Note that the nightly toolchain is required.
@@ -460,7 +462,7 @@ Keep these tips in mind while using Miri:
460
462
461
463
{{< details "Example to try: Miri in action" >}}
462
464
463
-
The test below should pass or fail on the assertion. Miri would detect undefined behavior.
465
+
The test below may pass or fail normally, but Miri should report undefined behavior.
464
466
465
467
```rust
466
468
fn main() { println!("Hello, world!"); }
@@ -509,17 +511,17 @@ To use proptest, you must write unit tests. But instead of hard-coding values th
509
511
510
512
Proptest ships with many [configurable strategies](https://docs.rs/proptest/latest/proptest/):
511
513
512
-
* Range-like generator for integers
513
-
* Regex generator for strings
514
-
* Simple generators for `bit`, `bool`, and `char` values
515
-
* Random-size generators for `std::collections`
514
+
* Range-like generator for integers
515
+
* Regex generator for strings
516
+
* Simple generators for `bit`, `bool`, and `char` values
517
+
* Random-size generators for `std::collections`
516
518
* Generators for `Option` and `Result`
517
519
518
520
The generators [can be combined together](https://proptest-rs.github.io/proptest/proptest/tutorial/macro-prop-compose.html). You can also use the following `Strategy` methods and the `prop_oneof!` macro to further combine and restrict generation:
519
521
520
-
* Do mapping with the `prop_map` method
521
-
* Do filtering with the `prop_filter` method
522
-
* Create enums with the `prop_oneof!` macro
522
+
* Do mapping with the `prop_map` method
523
+
* Do filtering with the `prop_filter` method
524
+
* Create enums with the `prop_oneof!` macro
523
525
* Do recursion with the `prop_recursive` method
524
526
525
527
Let’s see some example code:
@@ -608,13 +610,13 @@ cargo +nightly miri test
608
610
609
611
{{< /hint >}}
610
612
611
-
Finally, use our [`property-based-testing`](https://github.com/trailofbits/skills/tree/main/plugins/property-based-testing)Claude skill to automate the testing.
613
+
Finally, use our [`property-based-testing`](https://github.com/trailofbits/skills/tree/main/plugins/property-based-testing) skill to automate the testing.
612
614
613
615
## Coverage
614
616
615
617
It is critically important to know how much coverage your tests have. Coverage gathering consists of four steps:
616
618
617
-
* Compile-time instrumentation
619
+
* Compile-time instrumentation
618
620
* Execution of tests, producing "raw" data
619
621
* Merge of per-execution run results
620
622
* Conversion of merged data to a usable format (like an HTML report)
@@ -680,7 +682,7 @@ While checking coverage statistics from a command line and using one of many cov
680
682
| HTML output/tool |`grcov`|`llvm-cov`|`tarpaulin`|
| Expands Rust’s generics? | No |`--show-instantiations`| No |
685
687
| Includes number of hits? | Yes | Yes | Yes |
686
688
| Supports multi-file output? | Yes | Yes | No |
@@ -730,11 +732,11 @@ While checking coverage statistics from a command line and using one of many cov
730
732
731
733
These are our general recommendations for generating test coverage:
732
734
733
-
* Use `llvm-cov` (with [`llvm-cov-pretty`](https://crates.io/crates/llvm-cov-pretty)) for rapid testing. It is the easiest to run, it resolves generics, and it produces pretty HTML output.
734
-
* Use either `llvm-cov` or `grcov` for complex projects. Both are decent and can produce readable outputs.
735
-
* Use `tarpaulin` when other tools work incorrectly. [The developers claim](https://github.com/xd009642/tarpaulin?tab=readme-ov-file#nuances-with-llvm-coverage) that this can happen in the event of the following:
736
-
* The code panics unexpectedly.
737
-
* There are race conditions.
735
+
* Use `llvm-cov` (with [`llvm-cov-pretty`](https://crates.io/crates/llvm-cov-pretty)) for rapid testing. It is the easiest to run, it resolves generics, and it produces pretty HTML output.
736
+
* Use either `llvm-cov` or `grcov` for complex projects. Both are decent and can produce readable outputs.
737
+
* Use `tarpaulin` when other tools work incorrectly. [The developers claim](https://github.com/xd009642/tarpaulin?tab=readme-ov-file#nuances-with-llvm-coverage) that this can happen in the event of the following:
738
+
* The code panics unexpectedly.
739
+
* There are race conditions.
738
740
* The code forks.
739
741
740
742
For profiling, consider using [`measureme`](https://github.com/rust-lang/measureme), possibly with [Miri and Chrome DevTools](https://medium.com/source-and-buggy/data-driven-performance-optimization-with-rust-and-miri-70cb6dde0d35).
@@ -756,16 +758,16 @@ For starters, you need basic but decent unit test coverage. Then, use one of the
* Two parsing modes: regexes and [Comby](https://github.com/comby-tools/comby)
768
+
* Multiple languages supported
769
+
* Requires more manual setup than `cargo-mutants`
770
+
* Two parsing modes: regexes and [Comby](https://github.com/comby-tools/comby)
769
771
* Trivial Compiler Equivalence (TCE) optimization to eliminate redundant mutants before test runs
770
772
771
773
### Bugs in existing tests
@@ -833,6 +835,6 @@ The tool produces a `necessist.db` file that can be used to resume an interrupte
833
835
834
836
## Resources
835
837
836
-
*["The Rust Programming Language," chapter 11: Testing](https://web.mit.edu/rust-lang_v1.25/arch/amd64_ubuntu1404/share/doc/rust/html/book/second-edition/ch11-00-testing.html): The basics of unit and integration testing in Rust
837
-
*[Ed Page’s "Iterating on Testing in Rust"](https://epage.github.io/blog/2023/06/iterating-on-test/): Lists potential issues with `cargo``test` and introduces `cargo-nextest`
838
+
*["The Rust Programming Language," chapter 11: Testing](https://web.mit.edu/rust-lang_v1.25/arch/amd64_ubuntu1404/share/doc/rust/html/book/second-edition/ch11-00-testing.html): The basics of unit and integration testing in Rust
839
+
*[Ed Page’s "Iterating on Testing in Rust"](https://epage.github.io/blog/2023/06/iterating-on-test/): Lists potential issues with `cargo``test` and introduces `cargo-nextest`
838
840
*[Unsafe Rust and Miri by Ralf Jung \- Rust Zürisee June 2023](https://www.youtube.com/watch?v=svR0p6fSUYY)
Copy file name to clipboardExpand all lines: content/docs/languages/rust/30-static-analysis.md
+11-11Lines changed: 11 additions & 11 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -14,8 +14,8 @@ Clippy is the fundamental linter. Just use it.
14
14
15
15
[Clippy lints](https://rust-lang.github.io/rust-clippy/master/index.html) are categorized into groups and levels. Groups categorize lints by the types of issues they detect. Levels indicate what to do when a lint finds an issue:
16
16
17
-
* Allow: Ignore the issue
18
-
* Warn: Print a message to stderr
17
+
* Allow: Ignore the issue
18
+
* Warn: Print a message to stderr
19
19
* Deny: Return an error code (useful in CI pipelines)
20
20
21
21
Clippy is a wrapper over the `rustc` compiler, so when Clippy is run, it executes [its own set of lints](https://doc.rust-lang.org/rustc/lints/listing/index.html) in addition to `rustc`’s. These lints are similarly categorized and can be controlled with the same flags and configuration options.
For continuous use, such as in a CI/CD pipeline, you want to minimize false positives and focus on the important lints. For that, follow these guidelines:
77
77
78
-
* Use the default Clippy configuration.
79
-
* Enable recommended `clippy::restriction` lints (see the example below).
80
-
* Enable selected lints from `clippy::pedantic` groups (these should be enabled case by case depending on your project).
81
-
* Turn warnings into errors so that CI/CD fails on any issue.
78
+
* Use the default Clippy configuration.
79
+
* Enable recommended `clippy::restriction` lints (see the example below).
80
+
* Enable selected lints from `clippy::pedantic` groups (these should be enabled case by case depending on your project).
81
+
* Turn warnings into errors so that CI/CD fails on any issue.
82
82
* Add `#[allow(..)]` attributes in the code to silence specific findings of enabled lints when really needed. Make sure to comment why the lint was disabled in the specific location.
83
83
84
84
```sh
@@ -106,9 +106,9 @@ allow-unwrap-in-tests = true
106
106
107
107
[Dylint](https://github.com/trailofbits/dylint) runs lints from dynamic libraries named by the user, allowing developers to maintain their own personal lint collections. While you could write new Clippy lints and send a pull request, this is not always an ideal solution:
108
108
109
-
* The new lints cannot be project-specific.
110
-
* The new lints cannot target third-party crates.
111
-
* Complex lints may not be wanted due to maintenance effort.
109
+
* The new lints cannot be project-specific.
110
+
* The new lints cannot target third-party crates.
111
+
* Complex lints may not be wanted due to maintenance effort.
112
112
* Lints with a high false-positive rate may not be wanted.
113
113
114
114
Moreover, writing lints with Dylint instead of forking Clippy [helps with dealing with the unstable `rustc` API and with sharing lints with other people](https://blog.trailofbits.com/2021/11/09/write-rust-lints-without-forking-clippy/).
@@ -138,8 +138,8 @@ cargo dylint \
138
138
139
139
You can write your own lint, but it is a nontrivial task and is beyond the scope of this chapter. At a high level, you will need to decide on the type of lint:
140
140
141
-
* Pre-expansion: Run on the AST before macros are expanded
142
-
* Early: Run on the AST after macros have been expanded
141
+
* Pre-expansion: Run on the AST before macros are expanded
142
+
* Early: Run on the AST after macros have been expanded
143
143
* Late: Run on the high-level intermediate representation (HIR)—that is, after names have been resolved, types have been checked, etc.
144
144
145
145
Check out [Samuel Moelius’s ‘Linting with Dylint’ EuroRust 2024](https://youtu.be/MjlPUA7sAmA?t=548) talk for detailed guidelines.
Copy file name to clipboardExpand all lines: content/docs/languages/rust/40-gotchas.md
+6-6Lines changed: 6 additions & 6 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -16,8 +16,8 @@ This section provides a checklist that can be used during manual Rust code revie
16
16
- Often partial-match (`starts_with`, `ends_with`, `contains`) is used instead of equality.
17
17
- Case (in)sensitivity of comparisons often results in issues.
18
18
-[ ] Check string conversions to other data types (like `Vec`) and vice versa. These may come with UTF-8 encoding issues. Options for handling bytes that may not be valid UTF-8:
19
-
-`from_utf8` with `unwrap`—strict, panics on non-convertible data
20
-
-`from_utf8_lossy`—lossy, replaces invalid UTF-8 sequences with U+FFFD (replacement character)
19
+
-`from_utf8` with `unwrap`—strict, panics on non-convertible data
20
+
-`from_utf8_lossy`—lossy, replaces invalid UTF-8 sequences with U+FFFD (replacement character)
21
21
-`OsStr`/`OsString`—for platform-native strings that may not be valid UTF-8 (e.g., paths, environment variables, and `argv`); it is not a UTF-8/bytes converter, and there is no portable way to get its raw bytes (`as_bytes` is Unix-only; `as_encoded_bytes` uses a non-portable encoding)
22
22
-[ ] Verify that the `with_capacity` method of the `Vec`, `HashMap`, `HashSet`, and `indexmap::IndexSet` types (and possibly other types) is not called with user-controlled data. Large values can lead to denial of service.
23
23
- Also check that the provided capacity is smaller than the `isize::MAX` bytes [to prevent panics](https://doc.rust-lang.org/std/vec/struct.Vec.html#panics).
@@ -62,14 +62,14 @@ Common issues to check for in unsafe code are given below. For more information,
62
62
63
63
{{< checklist >}}
64
64
65
-
-[ ] Any union access is unsafe in Rust. Verify that the union field that matches the underlying data is used.
66
-
-[ ] Look for uses of libc APIs like `memset` or `memcpy`. Most of them can be replaced with safe Rust counterparts.
65
+
-[ ] Any union access is unsafe in Rust. Verify that the union field that matches the underlying data is used.
66
+
-[ ] Look for uses of libc APIs like `memset` or `memcpy`. Most of them can be replaced with safe Rust counterparts.
67
67
-[ ] If `#[repr(packed)]` is used on a struct, then check that `read_unaligned`/[`write_unaligned`](https://doc.rust-lang.org/std/ptr/fn.write_unaligned.html#on-packed-structs) is used for unaligned fields.
68
68
-[ ] Check for uses of [`std::mem::uninitialized`](https://doc.rust-lang.org/std/mem/fn.uninitialized.html) and `mem::zeroed`.
69
69
-[ ] Review uses of `MaybeUninit` to ensure that all calls to `assume_init` are preceded by initialization.
70
70
- Ensure that dropping of partially initialized data is implemented correctly.
71
-
-[ ] Check for uses of [`std::mem::forget`](https://doc.rust-lang.org/std/mem/fn.forget.html).
72
-
-[ ] Check for uses of `transmute` or `cast` from a non-mutable reference `&` to a mutable `&mut` (likely an undefined behavior).
71
+
-[ ] Check for uses of [`std::mem::forget`](https://doc.rust-lang.org/std/mem/fn.forget.html).
72
+
-[ ] Check for uses of `transmute` or `cast` from a non-mutable reference `&` to a mutable `&mut` (likely undefined behavior).
73
73
- Using [`bytemuck`](https://docs.rs/bytemuck/latest/bytemuck/) or [`zerocopy`](https://docs.rs/zerocopy/latest/zerocopy/) crates may be a safer alternative.
74
74
-[ ] Review uses of `static mut` and [recommend using synchronization instead](https://github.com/rust-lang/rust/issues/53639).
75
75
-[ ] Review uses of [unsafe attributes](https://github.com/rust-lang/rfcs/blob/master/text/3325-unsafe-attributes.md) like `#[unsafe(no_mangle)]`.
0 commit comments