GaloisInc / saw-script

The SAW scripting language.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

--detect-vacuity doesn't work with the MIR backend

sauclovian-g opened this issue · comments

saw --detect-vacuity foo.saw doesn't detect unsatisfiable preconditions (such as a == 0 /\ b == 1 /\ a == b) when using the MIR (Rust) backend.

Here is a test case:

// test.c
void fun_c() {}
// test.rs
pub fn fun_rs() {}
// test.saw
enable_experimental;

let fun_c_spec = do {
  x <- llvm_fresh_var "x" (llvm_int 32);
  llvm_precond {{ x != x }};
  llvm_execute_func [];
};
llvm_mod <- llvm_load_module "test.bc";
llvm_verify llvm_mod "fun_c" [] false fun_c_spec z3;

let fun_rs_spec = do {
  x <- mir_fresh_var "x" mir_u32;
  mir_precond {{ x != x }};
  mir_execute_func [];
};
mir_mod <- mir_load_module "test.linked-mir.json";
mir_verify mir_mod "test::fun_rs" [] false fun_rs_spec z3;
$ clang -g -emit-llvm -c test.c
$ saw-rustc test.rs
$ ~/Software/saw-1.1/bin/saw test.saw --detect-vacuity
[00:07:29.925] Loading file "test.saw"
[00:07:29.963] Verifying fun_c ...
[00:07:29.982] Contradiction detected! Computing minimal core of contradictory assumptions:
[00:07:30.017] ConditionMetadata {conditionLoc = ProgramLoc {plFunction = llvm_precond, plSourceLoc = /home/ryanscott/Documents/Hacking/SAW/test.saw:6:3}, conditionTags = fromList [], conditionType = "specification assertion", conditionContext = ""}: precondition
[00:07:30.017] Because of the contradiction, the following proofs may be vacuous.
[00:07:30.017] Simulating fun_c ...
[00:07:30.017] Checking proof obligations fun_c ...
[00:07:30.017] Proof succeeded! fun_c
[00:07:30.057] Verifying test/569fd098::fun_rs[0] ...
[00:07:30.068] Simulating test/569fd098::fun_rs[0] ...
[00:07:30.068] Checking proof obligations test/569fd098::fun_rs[0] ...
[00:07:30.068] Proof succeeded! test/569fd098::fun_rs[0]

Note that SAW prints Contradiction detected! for the llvm_verify invocation, but not the mir_verify one.

The reason this happens is because --detect-vacuity only does anything in the LLVM backend:

when (detectVacuity opts)
$ checkAssumptionsForContradictions cc methodSpec tactic assumes

The MIR backend (as well as the JVM backend) simply don't perform this check. Most of the code in the checkAssumptionsForContradictions function is not LLVM-specific, and we could reasonably port it over to other backends:

-- | Checks whether the given list of assumptions contains a contradiction, and
-- if so, computes and displays a minimal set of contradictory assumptions.
checkAssumptionsForContradictions ::
(Crucible.HasPtrWidth (Crucible.ArchWidth arch), Crucible.HasLLVMAnn Sym) =>
LLVMCrucibleContext arch ->
MS.CrucibleMethodSpecIR (LLVM arch) ->
ProofScript () ->
[Crucible.LabeledPred Term AssumptionReason] ->
TopLevel ()
checkAssumptionsForContradictions cc methodSpec tactic assumes =
whenM
(assumptionsContainContradiction cc methodSpec tactic assumes)
(computeMinimalContradictingCore cc methodSpec tactic assumes)

We'd need to perform some mild refactoring to get rid of the LLVMCrucibleContext argument, but I don't expect that to be difficult.