Skip to content

Mutable static variables usage in contract verification trigger UB #3298

Open
@celinval

Description

@celinval

I tried this code:

static mut WRAP_COUNTER: Option<u32> = None;

/// This function is safe and should never crash. Counter starts at 0.
#[kani::modifies(std::ptr::addr_of!(WRAP_COUNTER))]
#[kani::ensures(|_| true)]
pub fn next() -> u32 {
    // Safe in single-threaded.
    unsafe {
        match &WRAP_COUNTER {
            Some(val) => {
                WRAP_COUNTER = Some(val.wrapping_add(1));
                *val
            }
            None => {
                WRAP_COUNTER = Some(0);
                0
            }
        }
    }
}

#[kani::proof_for_contract(next)]
fn check_next() {
    let _ret = next();
}

using the following command line invocation:

kani fixme.rs -Z function-contracts

with Kani version: 0.52.0

I expected to see this happen: Verification succeeds

Instead, this happened: Verification fails because WRAP_COUNTER is havoc and it can contain an invalid discriminant. Thus, the match statement unreachable block is reached.

Checking harness check_next...

VERIFICATION RESULT:
 ** 1 of 1359 failed
Failed Checks: unreachable code
 File: "static_mut.rs", line 14, in next_wrapper_5f5d0a::<std::option::Option<u32>>

VERIFICATION:- FAILED
Verification Time: 2.9701335s

Metadata

Metadata

Assignees

No one assigned

    Labels

    Z-ContractsIssue related to code contracts[C] BugThis is a bug. Something isn't working.[F] Spurious FailureIssues that cause Kani verification to fail despite the code being correct.

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions