File tree Expand file tree Collapse file tree 5 files changed +57
-5
lines changed
regression/cbmc-cover/block-assume-coverage Expand file tree Collapse file tree 5 files changed +57
-5
lines changed Original file line number Diff line number Diff line change 1+ // Test for issue #826: Basic blocks incorrectly considered covered
2+ // with unsatisfiable ASSUME statements
3+ //
4+ // This test demonstrates that basic blocks should only be marked as
5+ // covered when ALL instructions in the block can execute, including
6+ // ASSUME statements.
7+ //
8+ // Before the fix: Block 3 would be incorrectly marked as SATISFIED
9+ // because the coverage assertion was at the beginning of the block.
10+ // After the fix: Block 3 is correctly marked as FAILED because the
11+ // ASSUME statement is unsatisfiable (x >= 0 when x < 0).
12+
13+ int main ()
14+ {
15+ int x ;
16+
17+ // Block with satisfiable ASSUME - should be covered
18+ if (x > 0 )
19+ {
20+ __CPROVER_assume (x > 0 );
21+ return 1 ;
22+ }
23+
24+ // Block with unsatisfiable ASSUME - should NOT be covered
25+ if (x < 0 )
26+ {
27+ __CPROVER_assume (x >= 0 );
28+ return 2 ;
29+ }
30+
31+ // Block with no ASSUME - should be covered
32+ return 0 ;
33+ }
Original file line number Diff line number Diff line change 1+ CORE
2+ main.c
3+ --cover location
4+ ^EXIT=0$
5+ ^SIGNAL=0$
6+ block 1 \(lines main.c:main:\d+\): SATISFIED
7+ block 2 \(lines main.c:main:\d+\): SATISFIED
8+ block 3 \(lines main.c:main:\d+\): FAILED
9+ block 4 \(lines main.c:main:\d+\): SATISFIED
10+ --
Original file line number Diff line number Diff line change @@ -63,6 +63,7 @@ cover_basic_blockst::cover_basic_blockst(const goto_programt &goto_program)
6363 else
6464 {
6565 block_infos.emplace_back ();
66+ // representative_inst will be updated to the last instruction
6667 block_infos.back ().representative_inst = it;
6768 block_infos.back ().source_location = source_locationt::nil ();
6869 current_block = block_infos.size () - 1 ;
@@ -77,15 +78,18 @@ cover_basic_blockst::cover_basic_blockst(const goto_programt &goto_program)
7778
7879 add_block_lines (block_info, *it);
7980
80- // set representative program location to instrument
81+ // Update representative instruction to always be the last instruction
82+ block_info.representative_inst = it;
83+
84+ // set source location for reporting (from first instruction with valid
85+ // location)
8186 if (
8287 !it->source_location ().is_nil () &&
8388 !it->source_location ().get_file ().empty () &&
8489 !it->source_location ().get_line ().empty () &&
8590 !it->source_location ().is_built_in () &&
8691 block_info.source_location .is_nil ())
8792 {
88- block_info.representative_inst = it; // update
8993 block_info.source_location = it->source_location ();
9094 }
9195
Original file line number Diff line number Diff line change @@ -74,7 +74,7 @@ class cover_basic_blockst final : public cover_blocks_baset
7474
7575 // / \param block_nr: a block number
7676 // / \return the instruction selected for
77- // / instrumentation representative of the given block
77+ // / instrumentation representative of the given block (last instruction)
7878 std::optional<goto_programt::const_targett>
7979 instruction_of (std::size_t block_nr) const override ;
8080
@@ -109,7 +109,7 @@ class cover_basic_blockst final : public cover_blocks_baset
109109
110110 struct block_infot
111111 {
112- // / the program location to instrument for this block
112+ // / the program location to instrument for this block (last instruction)
113113 std::optional<goto_programt::const_targett> representative_inst;
114114
115115 // / the source location representative for this block
Original file line number Diff line number Diff line change @@ -25,8 +25,13 @@ void cover_location_instrumentert::instrument(
2525 i_it->turn_into_skip ();
2626
2727 const std::size_t block_nr = basic_blocks.block_of (i_it);
28+
29+ // The representative instruction is the last instruction in the block,
30+ // ensuring all instructions (including any ASSUME statements) can be
31+ // executed.
2832 const auto representative_instruction = basic_blocks.instruction_of (block_nr);
29- // we only instrument the selected instruction
33+
34+ // we only instrument the selected instruction (last in block)
3035 if (representative_instruction && *representative_instruction == i_it)
3136 {
3237 const std::string b = std::to_string (block_nr + 1 ); // start with 1
You can’t perform that action at this time.
0 commit comments