// We test the `align_offset` panic below, make sure we test the interpreter impl and not the "real" one.
//@compile-flags: -Zmiri-symbolic-alignment-check
#![feature(never_type)]
#![allow(unconditional_panic, non_fmt_panics)]
use std::cell::Cell;
use std::panic::{catch_unwind, AssertUnwindSafe};
use std::process;
thread_local! {
static MY_COUNTER: Cell<usize> = Cell::new(0);
static DROPPED: Cell<bool> = Cell::new(false);
static HOOK_CALLED: Cell<bool> = Cell::new(false);
}
struct DropTester;
impl Drop for DropTester {
fn drop(&mut self) {
DROPPED.with(|c| {
c.set(true);
});
}
}
fn do_panic_counter(do_panic: impl FnOnce(usize) -> !) {
// If this gets leaked, it will be easy to spot
// in Miri's leak report
let _string = "LEAKED FROM do_panic_counter".to_string();
// When we panic, this should get dropped during unwinding
let _drop_tester = DropTester;
// Check for bugs in Miri's panic implementation.
// If do_panic_counter() somehow gets called more than once,
// we'll generate a different panic message and stderr will differ.
let old_val = MY_COUNTER.with(|c| {
let val = c.get();
c.set(val + 1);
val
});
do_panic(old_val);
}
#[kani::proof]
fn main() {
// Built-in panics; also make sure the message is right.
test(Some("index out of bounds: the len is 3 but the index is 4"), |_old_val| {
let _val = [0, 1, 2][4];
process::abort()
});
}
fn test(expect_msg: Option<&str>, do_panic: impl FnOnce(usize) -> !) {
// Reset test flags.
DROPPED.with(|c| c.set(false));
HOOK_CALLED.with(|c| c.set(false));
// Cause and catch a panic.
let res = catch_unwind(AssertUnwindSafe(|| {
let _string = "LEAKED FROM CLOSURE".to_string();
do_panic_counter(do_panic)
}))
.expect_err("do_panic() did not panic!");
}
I tried this code:
using the following command line invocation:
with Kani version:
I expected to see this happen: explanation
Instead, this happened: explanation