I built FerroProve to lift small C modules like parsers, checksums, byte-level helpers and more into crates that compile under #![forbid(unsafe_code)], with a separate extern "C" shim (ffi.rs) and .h header so existing C callers can link without changes.
c2rust transpile preserves raw pointer arithmetic inside unsafe, so an out of bounds read in C stays an out-of-bounds read in Rust. An LLM rewrite avoids unsafe but can change behavior on signed promotions or off by one inputs.
FerroProve pairs the lift with a differential check (what i mean is):
- Each vector runs under legacy C indexing semantics and against the lifted slice-based crate. Valid inputs must match byte-for-byte; an out-of-bounds C read or write must come back as
-100in the safe crate. - The emitted crate is compiled with
rustc --edition 2021 -D warningswith#![forbid(unsafe_code)]onlib.rs.
The top bar takes a GitHub .c URL. Nine upstream files are pre-wired as presets:
DaveGamble/cJSONv1.0.0cJSON.c(parse_hex4, CVE-2016-4303 over-read on a truncated\uescape)torvalds/linuxv6.8lib/crc8.cmadler/zlibv1.3.1adler32.credis/redis7.2src/crc16.cgcc-mirror/gcclibiberty/crc32.cesmil/muslsrc/stdlib/atoi.copenbsd/srclib/libc/string/timingsafe_bcmp.cgit/gitv2.30.0hex.c(hex_to_bytes)jedisct1/libsodium1.0.19sodium/utils.c(sodium_memcmp)
Constructs outside the supported subset (goto, **, heap allocation) are rejected with a line number rather than falling back to unsafe.
If you have a small C function that breaks it or produces an awkward ffi.rs signature, I'd like to see it.
1 post - 1 participant
