Crates.io | checkers |
lib.rs | checkers |
version | 0.6.3 |
source | src |
created_at | 2020-01-18 05:19:30.10461 |
updated_at | 2023-03-22 13:30:40.480271 |
description | A sanity checker for global allocations. |
homepage | https://github.com/udoprog/checkers |
repository | https://github.com/udoprog/checkers |
max_upload_size | |
id | 199644 |
size | 81,242 |
Checkers is a simple allocation sanitizer for Rust. It plugs in through the global allocator and can sanity check your unsafe Rust during integration testing. Since it plugs in through the global allocator it doesn't require any additional dependencies and works for all platforms - but it is more limited in what it can verify.
It can check for the following things:
What it can't do:
Add checkers
as a dev-dependency to your project:
checkers = "0.6.2"
Replace the global allocator in a test file and wrap tests you wish to
memory sanitise with #[checkers::test]
:
#[global_allocator]
static ALLOCATOR: checkers::Allocator = checkers::Allocator::system();
#[checkers::test]
fn test_allocations() {
let _ = Box::into_raw(Box::new(42));
}
Note that it's important that you write your test as an integration test by adding it to your
tests/
folder to isolate the use of the global allocator.
With the default feature set, this library performs diagnostics which will produce undefined behavior. Therefore, it is recommended that you only use checkers for testing, and never in any production code.
If you want to avoid this, you'll have to disable the realloc
and zeroed
features, but this will also produce less actionable diagnostics.
In a future release, this behavior will be changed to be opt-in through feature flags instead of enabled by default.
The following are features available, that changes how checkers work.
realloc
- Enabling this feature causes checker to verify that a realloc
operation is correctly implemented. That bytes from the old region were
faithfully transferred to the new, resized one.
Since this can have a rather significant performance impact, it can be
disabled.
Note that this will produce undefined behavior (#1) by reading uninitialized
memory, and should only be enabled to provide diagnostics on a best-effort
basis.zeroed
- Enabling this feature causes checkers to verify that a call to
alloc_zeroed produces a region where all bytes are set to zero.
Note that if the underlying allocator is badly implemented this will produce
undefined behavior (#1) since it could read uninitialized memory.macros
- Enables dependencies and re-exports of macros, like
#[checkers::test]
.backtrace
- Enables the capture and rendering of backtraces. If
disabled, any fields containing backtraces will be None
.It is recommended that you use checkers for integration tests, which by
default lives in the ./tests
directory. Each file in this directory will be
compiled as a separate program, so the use of the global allocator can be more
isolated.
We then use checkers by installing
checkers::Allocator
as the global allocator, after
this we can make use of #[checkers::test]
attribute macro
or the checkers::with
function in our tests.
#[global_allocator]
static ALLOCATOR: checkers::Allocator = checkers::Allocator::system();
#[checkers::test]
fn test_allocations() {
let _ = Box::into_raw(Box::new(42));
}
The above would result in the following test output:
dangling region: 0x226e5784f30-0x226e5784f40 (size: 16, align: 8).
thread 'test_leak_box' panicked at 'allocation checks failed', tests\leaky_tests.rs:4:1
With checkers::with
, we can perform more detailed
diagnostics:
#[global_allocator]
static ALLOCATOR: checkers::Allocator = checkers::Allocator::system();
#[test]
fn test_event_inspection() {
let snapshot = checkers::with(|| {
let _ = vec![1, 2, 3, 4];
});
assert_eq!(2, snapshot.events.len());
assert!(snapshot.events[0].is_alloc_with(|r| r.size >= 16));
assert!(snapshot.events[1].is_free_with(|a| a.size >= 16));
assert_eq!(1, snapshot.events.allocs());
assert_eq!(1, snapshot.events.frees());
assert!(snapshot.events.max_memory_used().unwrap() >= 16);
}