diff --git a/kani-driver/src/cbmc_property_renderer.rs b/kani-driver/src/cbmc_property_renderer.rs index bdc16f72c595..7334ef780080 100644 --- a/kani-driver/src/cbmc_property_renderer.rs +++ b/kani-driver/src/cbmc_property_renderer.rs @@ -513,7 +513,7 @@ pub fn postprocess_result(properties: Vec, extra_ptr_checks: bool) -> let updated_properties = update_properties_with_reach_status(properties_filtered, has_fundamental_failures); let results_after_code_coverage = update_results_of_code_coverage_checks(updated_properties); - update_results_of_cover_checks(results_after_code_coverage) + update_results_of_cover_checks(results_after_code_coverage, has_failed_unwinding_asserts) } /// Determines if there is property with status `FAILURE` and the given description @@ -649,8 +649,15 @@ fn update_results_of_code_coverage_checks(mut properties: Vec) -> Vec< /// `update_properties_with_reach_status` is called beforehand /// /// Although regular cover properties do not fail verification, contract cover properties do. -/// If the assert(!cond) fails as expected, succeed; otherwise, fail. -fn update_results_of_cover_checks(mut properties: Vec) -> Vec { +/// If the assert(!cond) is unreachable or successful, then fail. +/// Also fail if the status is undetermined and there are failed unwinding asserts; if we didn't unwind enough, +/// we know that the postcondition is unreachable. +/// If the status is undetermined for another reason (e.g., unsupported constructs), leave the result as undetermined. +/// If the status is failure (as expected), succeed. +fn update_results_of_cover_checks( + mut properties: Vec, + has_failed_unwinding_asserts: bool, +) -> Vec { for prop in properties.iter_mut() { if prop.is_cover_property() { if prop.status == CheckStatus::Success { @@ -661,7 +668,7 @@ fn update_results_of_cover_checks(mut properties: Vec) -> Vec u8 { + unsafe { + std::arch::asm!("nop"); + } + *x +} diff --git a/tests/expected/function-contract/cover_contract/unreachable_postcondition.rs b/tests/expected/function-contract/cover_contract/unreachable_postcondition.rs index 982a04f4c63c..182a5e90b207 100644 --- a/tests/expected/function-contract/cover_contract/unreachable_postcondition.rs +++ b/tests/expected/function-contract/cover_contract/unreachable_postcondition.rs @@ -2,12 +2,15 @@ // SPDX-License-Identifier: Apache-2.0 OR MIT // kani-flags: -Zfunction-contracts -// Test `conver_contract` functionality, which fails verification for a vacuous precondition +// Test `cover_contract` functionality, which fails verification for a unsatisfiable precondition // or unreachable postcondition. // See https://github.com/model-checking/kani/issues/2793 -// Unreachable postcondition. +// Test that verification fails for an unreachable postcondition. + // The precondition is satisfiable, but the postcondition is unreachable because the code panics. +// Test that in the case where the postcondition check's property status is unreachable (because the function panics) +// we change the status to failure. #[kani::requires(a > 5)] #[kani::ensures(|result: &u32| *result == a)] fn unreachable_postcondition(a: u32) -> u32 { @@ -20,13 +23,15 @@ fn prove_unreachable_postcondition() { unreachable_postcondition(x); } +// Unreachable postcondition because the function never returns. +// Test that in the case where the postcondition check's property status is undetermined because of unwinding failures, +// we change the status to failure. #[kani::ensures(|result: &u32| *result == 7)] fn never_return() -> u32 { loop {} 7 } -// Unreachable postcondition because the function never returns #[kani::proof_for_contract(never_return)] #[kani::unwind(5)] fn prove_never_return() { diff --git a/tests/expected/function-contract/cover_contract/vacuous_precondition.expected b/tests/expected/function-contract/cover_contract/unsatisfiable_precondition.expected similarity index 100% rename from tests/expected/function-contract/cover_contract/vacuous_precondition.expected rename to tests/expected/function-contract/cover_contract/unsatisfiable_precondition.expected diff --git a/tests/expected/function-contract/cover_contract/vacuous_precondition.rs b/tests/expected/function-contract/cover_contract/unsatisfiable_precondition.rs similarity index 65% rename from tests/expected/function-contract/cover_contract/vacuous_precondition.rs rename to tests/expected/function-contract/cover_contract/unsatisfiable_precondition.rs index 27f239a3f08c..80b7ac3b0e5c 100644 --- a/tests/expected/function-contract/cover_contract/vacuous_precondition.rs +++ b/tests/expected/function-contract/cover_contract/unsatisfiable_precondition.rs @@ -2,11 +2,14 @@ // SPDX-License-Identifier: Apache-2.0 OR MIT // kani-flags: -Zfunction-contracts -// Test `conver_contract` functionality, which fails verification for a vacuous precondition +// Test `cover_contract` functionality, which fails verification for an unsatisfiable precondition // or unreachable postcondition. // See https://github.com/model-checking/kani/issues/2793 -// Vacuous precondition; separate requires clauses +// Test that verification fails for unsatisfiable preconditions. + +// Unsatisfiable precondition; separate requires clauses. +// The postcondition is unreachable because of the unsatisfiable precondition. #[kani::requires(a > 5)] #[kani::requires(a < 4)] #[kani::ensures(|result: &u32| *result == a)] @@ -20,7 +23,8 @@ fn prove_separate_requires() { separate_requires(x); } -// Vacuous precondition; single requires clause +// Unsatisfiable precondition; single requires clause +// The postcondition is unreachable because of the unsatisfiable precondition. #[kani::requires(a > 5 && a < 4)] #[kani::ensures(|result: &u32| *result == a)] fn conjoined_requires(a: u32) -> u32 {