From 4dd6619b4ce609f196c0b521b6382225c348a365 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Fri, 4 Feb 2022 14:02:12 -0800 Subject: [PATCH] Add miri builder This adds a builder to run `cargo miri` in order to check for certain classes of undefined behavior. One thing to note is that we've had to parameterize a number of tests to use a smaller cycle count under miri. This is because miri's stacked borrows checker is superlinear: https://github.com/rust-lang/miri/issues/1367 This can cause the miri builder to run out of memory. To avoid this, we reduce the cycle counts for a few tests that are particularly expensive when we're running inside miri. --- .github/workflows/ci.yml | 15 +++++++++++++++ src/map.rs | 2 +- src/set.rs | 2 +- tests/quick.rs | 41 +++++++++++++++++++++++++++++++++++++--- 4 files changed, 55 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b4505705..79cc3d8a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -93,3 +93,18 @@ jobs: components: clippy - run: cargo clippy + miri: + runs-on: ubuntu-latest + strategy: + matrix: + rust: + - nightly + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.rust }} + override: true + components: miri + - run: cargo miri test diff --git a/src/map.rs b/src/map.rs index 9cda12cb..56330470 100644 --- a/src/map.rs +++ b/src/map.rs @@ -1567,7 +1567,7 @@ mod tests { let mut keys = vec![]; keys.extend(0..16); - keys.extend(128..267); + keys.extend(if cfg!(miri) { 32..64 } else { 128..267 }); for &i in &keys { let old_map = map.clone(); diff --git a/src/set.rs b/src/set.rs index be4d7fb4..50b86647 100644 --- a/src/set.rs +++ b/src/set.rs @@ -1426,7 +1426,7 @@ mod tests { let mut values = vec![]; values.extend(0..16); - values.extend(128..267); + values.extend(if cfg!(miri) { 32..64 } else { 128..267 }); for &i in &values { let old_set = set.clone(); diff --git a/tests/quick.rs b/tests/quick.rs index 5376e75a..6c6cc034 100644 --- a/tests/quick.rs +++ b/tests/quick.rs @@ -1,9 +1,9 @@ use indexmap::{IndexMap, IndexSet}; use itertools::Itertools; -use quickcheck::quickcheck; use quickcheck::Arbitrary; use quickcheck::Gen; +use quickcheck::QuickCheck; use quickcheck::TestResult; use fnv::FnvHasher; @@ -39,7 +39,42 @@ where IndexMap::from_iter(iter.into_iter().copied().map(|k| (k, ()))) } -quickcheck! { +// Helper macro to allow us to use smaller quickcheck limits under miri. +macro_rules! quickcheck_limit { + (@as_items $($i:item)*) => ($($i)*); + { + $( + $(#[$m:meta])* + fn $fn_name:ident($($arg_name:ident : $arg_ty:ty),*) -> $ret:ty { + $($code:tt)* + } + )* + } => ( + quickcheck::quickcheck! { + @as_items + $( + #[test] + $(#[$m])* + fn $fn_name() { + fn prop($($arg_name: $arg_ty),*) -> $ret { + $($code)* + } + let mut quickcheck = QuickCheck::new(); + if cfg!(miri) { + quickcheck = quickcheck + .gen(Gen::new(10)) + .tests(10) + .max_tests(100); + } + + quickcheck.quickcheck(prop as fn($($arg_ty),*) -> $ret); + } + )* + } + ) +} + +quickcheck_limit! { fn contains(insert: Vec) -> bool { let mut map = IndexMap::new(); for &key in &insert { @@ -260,7 +295,7 @@ where true } -quickcheck! { +quickcheck_limit! { fn operations_i8(ops: Large>>) -> bool { let mut map = IndexMap::new(); let mut reference = HashMap::new();