Skip to content

Commit e657818

Browse files
authored
(#686) Make analysis/test miri-compatible and add a miri test for it
Fixes #685. This makes `analysis/test` `miri`-compatible when running with `--features miri`. This is done by using a monomorphic `printf` shim, since `miri` can't handle variadic functions like `printf`. Since all uses of `printf` in `analysis/test` are monomorphic (they all have the same format string), we can substitute a `fn printf` that is non-`extern "C"`, non-variadic (and thus `miri`-compatible), and that still has the same behavior for its call sites. Then we add a test in `c2rust-pdg` that runs `miri` on `analysis/test` to ensure it stays UB-free. However, we don't yet run this test by default (it's `#[ignore]`d for now) as there are issues with running `miri` in CI (it installs `xargo` every time and I'm getting a permission denied error (not sure from quite what exactly), and it'd be better to install `xargo` upfront, not on every run). Thus, I'm `#[ignore]`ing it for now in 4152d34. We can get it to run in CI correctly later in another PR, but I want to merge this now and avoid over-complicating it here. The test can still be manually run with `cargo test -p c2rust-pdg -- --ignored analysis_test_miri`. See #698 for the tracking issue to re-enable this test by default. The new test passing is blocked on: * #683 (f ixes #680) * #684 (f ixes #681) It would also be nice to f ix #682, but that's not completely necessary for this (though it would create a much less noisy output).
2 parents 5bb01cb + 4152d34 commit e657818

File tree

4 files changed

+42
-1
lines changed

4 files changed

+42
-1
lines changed

analysis/test/Cargo.toml

+3
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,6 @@ edition = "2021"
88
[dependencies]
99
libc = "0.2"
1010
c2rust-analysis-rt = { path = "../runtime", optional = true, version = "0.1.0" }
11+
12+
[features]
13+
miri = []

analysis/test/src/pointers.rs

+25
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,34 @@ extern "C" {
1414
fn calloc(_: libc::c_ulong, _: libc::c_ulong) -> *mut libc::c_void;
1515
fn realloc(_: *mut libc::c_void, _: libc::c_ulong) -> *mut libc::c_void;
1616
fn free(__ptr: *mut libc::c_void);
17+
}
18+
19+
#[cfg(not(feature = "miri"))]
20+
extern "C" {
1721
fn printf(_: *const libc::c_char, _: ...) -> libc::c_int;
1822
}
1923

24+
/// `miri` does not support calling variadic functions like [`printf`],
25+
/// but we want to test for UB, leaks, etc. using `cargo miri run`.
26+
///
27+
/// Luckily, all [`printf`] calls in this module are monomorphic,
28+
/// in that they all have the same format string and same call signature,
29+
/// so we can replace it with a [`printf`] shim that preserves the behavior
30+
/// only for the exact monomorphic usages in this module.
31+
///
32+
/// Note that there is no way to detect `miri` is running,
33+
/// so we have to put this under a separate `miri` feature
34+
/// that should be enabled when testing under `miri` with
35+
/// `cargo miri run --features miri`.
36+
#[cfg(feature = "miri")]
37+
fn printf(fmt: *const libc::c_char, i: i32) -> libc::c_int {
38+
use std::ffi::CStr;
39+
assert_eq!(unsafe { CStr::from_ptr(fmt) }, CStr::from_bytes_with_nul(b"%i\n\x00").unwrap());
40+
let s = format!("{i}\n");
41+
print!("{s}");
42+
s.len() as libc::c_int
43+
}
44+
2045
/// Hidden from instrumentation so that we can polyfill [`reallocarray`] with it.
2146
const REALLOC: unsafe extern "C" fn(*mut libc::c_void, libc::c_ulong) -> *mut libc::c_void = realloc;
2247

pdg/src/main.rs

+13
Original file line numberDiff line numberDiff line change
@@ -365,4 +365,17 @@ mod tests {
365365
insta::assert_display_snapshot!(pdg);
366366
Ok(())
367367
}
368+
369+
#[test]
370+
#[ignore]
371+
fn analysis_test_miri() -> eyre::Result<()> {
372+
init();
373+
let mut cmd = Command::new("cargo");
374+
cmd.current_dir(repo_dir()?.join("analysis/test"))
375+
.args(&["miri", "run", "--features", "miri"])
376+
.env("MIRIFLAGS", "");
377+
let status = cmd.status()?;
378+
ensure!(status.success(), eyre!("{cmd:?} failed: {status}"));
379+
Ok(())
380+
}
368381
}

rust-toolchain.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
[toolchain]
22
channel = "nightly-2022-08-08"
3-
components = ["rustfmt-preview", "rustc-dev", "rust-src"]
3+
components = ["rustfmt-preview", "rustc-dev", "rust-src", "miri"]

0 commit comments

Comments
 (0)