Open roypat opened 1 year ago
The workaround provided in https://github.com/model-checking/kani/issues/2686 for a similar issue (importing the stubbing target by alias and stubbing our that alias) also works in this case:
#[allow(unused)]
mod stubs {
use libc::{c_int, c_long};
pub unsafe extern "C" fn sysconf(_input: c_int) -> c_long {
1
}
}
use libc::sysconf as sysconf_alias;
#[kani::proof]
#[kani::stub(sysconf_alias, stubs::sysconf)]
fn verify_sysconf_stub() {
assert_eq!(1, unsafe{ libc::sysconf(libc::_SC_PAGE_SIZE) });
}
leads to
RESULTS:
Check 1: verify_sysconf_stub.assertion.1
- Status: SUCCESS
- Description: "assertion failed: 1 == unsafe { libc::sysconf(libc::_SC_PAGE_SIZE) }"
- Location: src/main.rs:38:5 in function verify_sysconf_stub
SUMMARY:
** 0 of 1 failed
VERIFICATION:- SUCCESSFUL
Verification Time: 0.02846472s
Mhh, instead trying to stub out libc::clock_gettime
(which is something we'd like to do over at firecracker to make some of our ratelimiter proofs nicer), actually leads to a kani crash:
I tried
mod stubs {
pub unsafe extern "C" fn clock_gettime(_clock_id: libc::clockid_t, tp: *mut libc::timespec) -> libc::c_int {
unsafe {
(*tp).tv_sec = kani::any();
(*tp).tv_nsec = kani::any();
}
0
}
}
#[kani::proof]
#[kani::stub(libc::clock_gettime, stubs::clock_gettime)]
fn verify_clock_gettime_stub() {
let i = std::time::Instant::now();
}
and running RUST_BACKTRACE=1 cargo kani --enable-unstable --enable-stubbing
leads to
2023-08-16T11:04:50.845806Z ERROR cprover_bindings::goto_program::expr: Argument doesn't check param=Pointer { typ: StructTag("tag-libc::timespec") } arg=Pointer { typ: StructTag("tag-libc::unix::timespec") }
error: internal compiler error: Kani unexpectedly panicked at panicked at cprover_bindings/src/goto_program/expr.rs:661:9:
Function call does not type check:
func: Expr { value: Symbol { identifier: "_RNvNtCsgn0tUiWO6QV_10playground5stubs13clock_gettime" }, typ: Code { parameters: [Parameter { typ: Signedbv { width: 32 }, identifier: None, base_name: None }, Parameter { typ: Pointer { typ: StructTag("tag-libc::timespec") }, identifier: None, base_name: None }], return_type: Signedbv { width: 32 } }, location: None, size_of_annotation: None }
args: [Expr { value: Symbol { identifier: "_ZN3std3sys4unix4time5inner48_$LT$impl$u20$std..sys..unix..time..Timespec$GT$3now17hbf6b40abeb30b878E::1::var_1::clock" }, typ: Signedbv { width: 32 }, location: None, size_of_annotation: None }, Expr { value: Symbol { identifier: "_ZN3std3sys4unix4time5inner48_$LT$impl$u20$std..sys..unix..time..Timespec$GT$3now17hbf6b40abeb30b878E::1::var_6" }, typ: Pointer { typ: StructTag("tag-libc::unix::timespec") }, location: None, size_of_annotation: None }].
thread 'rustc' panicked at cprover_bindings/src/goto_program/expr.rs:661:9:
Function call does not type check:
func: Expr { value: Symbol { identifier: "_RNvNtCsgn0tUiWO6QV_10playground5stubs13clock_gettime" }, typ: Code { parameters: [Parameter { typ: Signedbv { width: 32 }, identifier: None, base_name: None }, Parameter { typ: Pointer { typ: StructTag("tag-libc::timespec") }, identifier: None, base_name: None }], return_type: Signedbv { width: 32 } }, location: None, size_of_annotation: None }
args: [Expr { value: Symbol { identifier: "_ZN3std3sys4unix4time5inner48_$LT$impl$u20$std..sys..unix..time..Timespec$GT$3now17hbf6b40abeb30b878E::1::var_1::clock" }, typ: Signedbv { width: 32 }, location: None, size_of_annotation: None }, Expr { value: Symbol { identifier: "_ZN3std3sys4unix4time5inner48_$LT$impl$u20$std..sys..unix..time..Timespec$GT$3now17hbf6b40abeb30b878E::1::var_6" }, typ: Pointer { typ: StructTag("tag-libc::unix::timespec") }, location: None, size_of_annotation: None }]
stack backtrace:
0: rust_begin_unwind
at /rustc/474709a9a2a74a8bcf0055fadb335d0ca0d2d939/library/std/src/panicking.rs:617:5
1: core::panicking::panic_fmt
at /rustc/474709a9a2a74a8bcf0055fadb335d0ca0d2d939/library/core/src/panicking.rs:67:14
2: cprover_bindings::goto_program::expr::Expr::call
3: kani_compiler::codegen_cprover_gotoc::codegen::statement::<impl kani_compiler::codegen_cprover_gotoc::context::goto_ctx::GotocCtx>::codegen_terminator
4: kani_compiler::codegen_cprover_gotoc::codegen::block::<impl kani_compiler::codegen_cprover_gotoc::context::goto_ctx::GotocCtx>::codegen_block
5: kani_compiler::codegen_cprover_gotoc::utils::debug::<impl kani_compiler::codegen_cprover_gotoc::context::goto_ctx::GotocCtx>::call_with_panic_debug_info
6: kani_compiler::codegen_cprover_gotoc::compiler_interface::GotocCodegenBackend::codegen_items
7: <kani_compiler::codegen_cprover_gotoc::compiler_interface::GotocCodegenBackend as rustc_codegen_ssa::traits::backend::CodegenBackend>::codegen_crate
8: <rustc_session::session::Session>::time::<alloc::boxed::Box<dyn core::any::Any>, rustc_interface::passes::start_codegen::{closure#0}>
9: rustc_interface::passes::start_codegen
10: <rustc_middle::ty::context::GlobalCtxt>::enter::<<rustc_interface::queries::Queries>::ongoing_codegen::{closure#0}, core::result::Result<alloc::boxed::Box<dyn core::any::Any>, rustc_span::ErrorGuaranteed>>
11: <rustc_interface::interface::Compiler>::enter::<rustc_driver_impl::run_compiler::{closure#1}::{closure#2}, core::result::Result<core::option::Option<rustc_interface::queries::Linker>, rustc_span::ErrorGuaranteed>>
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
Kani unexpectedly panicked during compilation.
Please file an issue here: https://github.com/model-checking/kani/issues/new?labels=bug&template=bug_report.md
[Kani] current codegen item: codegen_function: std::sys::unix::time::inner::<impl std::sys::unix::time::Timespec>::now
_ZN3std3sys4unix4time5inner48_$LT$impl$u20$std..sys..unix..time..Timespec$GT$3now17hbf6b40abeb30b878E
[Kani] current codegen location: Loc { file: "/github/home/.rustup/toolchains/nightly-2023-08-04-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/unix/time.rs", function: None, start_line: 397, start_col: Some(9), end_line: 397, end_col: Some(55) }
error: could not compile `playground` (bin "playground"); 10 warnings emitted
error: Failed to compile `playground` due to an internal compiler error.: error: internal compiler error: Kani unexpectedly panicked at panicked at cprover_bindings/src/goto_program/expr.rs:661:9:
Function call does not type check:
func: Expr { value: Symbol { identifier: "_RNvNtCsgn0tUiWO6QV_10playground5stubs13clock_gettime" }, typ: Code { parameters: [Parameter { typ: Signedbv { width: 32 }, identifier: None, base_name: None }, Parameter { typ: Pointer { typ: StructTag("tag-libc::timespec") }, identifier: None, base_name: None }], return_type: Signedbv { width: 32 } }, location: None, size_of_annotation: None }
args: [Expr { value: Symbol { identifier: "_ZN3std3sys4unix4time5inner48_$LT$impl$u20$std..sys..unix..time..Timespec$GT$3now17hbf6b40abeb30b878E::1::var_1::clock" }, typ: Signedbv { width: 32 }, location: None, size_of_annotation: None }, Expr { value: Symbol { identifier: "_ZN3std3sys4unix4time5inner48_$LT$impl$u20$std..sys..unix..time..Timespec$GT$3now17hbf6b40abeb30b878E::1::var_6" }, typ: Pointer { typ: StructTag("tag-libc::unix::timespec") }, location: None, size_of_annotation: None }].
I think this also is a result of the standard library using a "special" version of libc. I tried to match my libc crate version to the version the standard library was compiled against (and also tried all libc versions since 0.2.141), to no avail :(.
Using the rustc_private
feature avoids this
Right, so I found a workaround... ish
For some reason, rustc's libc is not a drop-in-replacement for crates.io libc, so just doing #![feature(rustc_private)]
will not work for arbitrary crates (e.g. firecracker). It also means that a nightly compiler would be required for normal builds, which is not ideal. I managed to get things to work by adding #![cfg_attr(kani, feature(rustc_private))]
and in my Cargo.toml libc_public = { package = "libc", version = "..." }
(and then put use libc_public as libc
at the top of each module that does not contain a kani libc stub). In modules for kani stubs, I instead do extern crate libc as rustc_libc
and write the stubs in terms of rustc_libc
(and this is what requires the "normal" libc crate to be renamed in Cargo.toml, as otherwise extern crate libc
will refer to the version from crates.io instead of the rustc internal one.
I think the problem here might be related to different versions of the same crate. The libc you are pulling from crates.io might not have the same version as the one that rustc_private points to, hence the mismatched type.
Your workaround makes sense to me, so you can clearly pinpoint which one you are trying to stub. That said, I think we are mishandling this case, and we should fix that. Let us know if you are blocked though.
I tried this code:
using the following command line invocation:
with Kani version: 0.34.0
I expected to see this happen: sysconf to be successfully stubbed and verification to succeed
Instead, this happened: sysconf was not stubbed out, and instead the CMBC model was used. Because of this, verification failed with
If I remove
libc
from myCargo.toml
and instead putat the top of my file, verification succeeds as expected. This is why the integration test added for the FFI stubbing feature added in #2658 passes.