https://github.com/trailofbits/cast_checks
A procedural macro to check for invalid casts
https://github.com/trailofbits/cast_checks
casting rust
Last synced: 9 months ago
JSON representation
A procedural macro to check for invalid casts
- Host: GitHub
- URL: https://github.com/trailofbits/cast_checks
- Owner: trailofbits
- License: apache-2.0
- Created: 2023-03-18T23:44:53.000Z (almost 3 years ago)
- Default Branch: master
- Last Pushed: 2025-03-03T16:31:29.000Z (11 months ago)
- Last Synced: 2025-03-28T12:51:18.403Z (10 months ago)
- Topics: casting, rust
- Language: Rust
- Homepage:
- Size: 44.9 KB
- Stars: 8
- Watchers: 11
- Forks: 3
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE-APACHE
- Codeowners: CODEOWNERS
Awesome Lists containing this project
README
# `cast_checks`
A procedural macro to check for invalid casts
Like [`-C overflow-checks`], `cast_checks` is enabled only for debug builds by default. To enable `cast_checks` for release builds, set the crate-level `release` feature.
## How it works
`cast_checks::enable` essentially rewrites each expression of the form:
```rust,ignore
expr as T
```
to an expression involving [`try_into`]:
```rust,ignore
<_ as TryInto::< T >>::try_into( expr ).expect("invalid cast")
```
So when an invalid cast occurs, a message like the following results:
```text
thread 'checked_truncation' panicked at 'invalid cast: TryFromIntError(())', cast_checks/tests/basic.rs:30:13
```
We say "essentially rewrites" because the actual generated code is slightly more complex. It uses [Nikolai Vazquez]'s [`impls`]' [trick] to determine whether an appropriate [`TryInto`] implementation exists.
## How to use
### With a stable compiler
You must use `cast_checks::enable` as an outer [attribute]. Example:
```rust
#[cast_checks::enable]
fn as_u16(x: u64) -> u16 {
x as u16
}
```
### With a nightly compiler
**We recommend enabling Rust features [`custom_inner_attributes`] and [`proc_macro_hygiene`].**
If you enable the [`custom_inner_attributes`] and [`proc_macro_hygiene`] features, you can use `cast_checks::enable` as an inner [attribute]. Example:
```rust,ignore
#![feature(custom_inner_attributes, proc_macro_hygiene)]
mod m {
#![cast_checks::enable]
/* items */
}
```
## `CAST_CHECKS_LOG`
If you are concerned that some casts are not being checked, try setting `CAST_CHECKS_LOG` and passing the [`procmacro2_semver_exempt`] config flag when compiling, e.g.:
```sh
CAST_CHECKS_LOG=1 RUSTFLAGS='--cfg procmacro2_semver_exempt' cargo build
```
This will cause `cast_checks` to dump to standard output:
- all rewritten locations
- all modules whose contents are not visited because they are not inlined
Example:
```text
cast_checks rewriting `x as u16` at src/lib.rs:3:0
cast_checks not descending into `mod c ;` at src/lib.rs:3:0
```
Note that `CAST_CHECKS_LOG` requires `--cfg procmacro2_semver_exempt` to be passed to rustc.
[`-c overflow-checks`]: https://doc.rust-lang.org/rustc/codegen-options/index.html#overflow-checks
[attribute]: https://doc.rust-lang.org/reference/attributes.html
[`custom_inner_attributes`]: https://github.com/rust-lang/rust/issues/54726
[`procmacro2_semver_exempt`]: https://github.com/dtolnay/proc-macro2#unstable-features
[`proc_macro_hygiene`]: https://github.com/rust-lang/rust/issues/54727
[`rustflags='--cfg procmacro2_semver_exempt'`]: https://github.com/dtolnay/proc-macro2#unstable-features
[nikolai vazquez]: https://github.com/nvzqz
[`impls`]: https://github.com/nvzqz/impls
[trick]: https://github.com/nvzqz/impls#how-it-works
[`tryinto`]: https://doc.rust-lang.org/std/convert/trait.TryInto.html
[`try_into`]: https://doc.rust-lang.org/std/convert/trait.TryInto.html#tymethod.try_into