model-checking/verify-rust-std

Challenge 13: Safety of `CStr`

Opened this issue · 2 comments

Edit: After discussion, we were recommended to implement the Invariant manually using ub_checks::Invariant, as similar to this code.


@celinval We (Team 2) decided to work on this challenge for a week while waiting for Kani issue #3711 to unblock #59 Part 3.

For Part 1, we are writing a safety invariant for CStr. From the doc and Kani PR#3270 we found that #[derive(Invariant)] macro and #[safety_constraint(...)] attribute look useful. We are thinking about writing the safety invariant in c_str.rs like:

#[cfg(kani)]
use crate::kani;

// Struct-level CStr safety invariant
#[derive(kani::Arbitrary)] // Might be useful when verifying methods that take a CStr as input
#[derive(kani::Invariant)]
#[safety_constraint(inner.len() > 0 && inner[inner.len() - 1] == 0 && !inner[..inner.len() - 1].contains(&0))]
pub struct CStr {
    // comments omitted
    inner: [c_char],
}

// Test harness
// pub const fn from_bytes_until_nul(bytes: &[u8]) -> Result<&CStr, FromBytesUntilNulError>
#[kani::proof]
#[kani::unwind(16)]  // Proof bounded by array length
fn check_from_bytes_until_nul() {
    const ARR_LEN: usize = 16;
    let mut string: [u8; ARR_LEN] = kani::any();
    // ensure that there is at least one null byte
    let idx: usize = kani::any_where(|x| *x >= 0 && *x < ARR_LEN);
    string[idx] = 0;

    let c_str = CStr::from_bytes_until_nul(&string).unwrap();
    assert!(c_str.is_safe());
}

However, the compilation of core (using the kani script) failed due to the following error:

error[E0404]: expected trait, found derive macro `core::kani::Invariant`
   --> /Users/yew005/Docs/Academic/CMU/Fall24/practicum/vrs/library/core/src/ffi/c_str.rs:109:10
    |
109 | #[derive(kani::Invariant)]
    |          ^^^^^^^^^^^^^^^ not a trait

We thought that this should be supported in Kani 0.54.0, but we were not able to compile. How could we fix it?

@rajathkotyal, @lanfeima, @MWDZ for visibility.

Upon some research, The compilation error could be due to the fact we are trying to include an external dep (kani::Invariant) into the source code compilation process, So even with the use of cfg["kani"] flag, the compiler tries to parse and resolve all macros and attributes. It cannot find kani::Invariant within the core crate.

There seems to be some ambiguity in the code / with my understanding. Some insight on this would help.