Skip to content

Commit f03192d

Browse files
committed
Fix basic block coverage with unsatisfiable ASSUME statements
Insert coverage assertions at the end of basic blocks instead of the beginning to ensure blocks are only marked as covered when all instructions, including ASSUME statements, can be executed. Fixes: #826
1 parent 4fe3ade commit f03192d

File tree

5 files changed

+57
-5
lines changed

5 files changed

+57
-5
lines changed
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
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+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
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+
--

src/goto-instrument/cover_basic_blocks.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff 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

src/goto-instrument/cover_basic_blocks.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff 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

src/goto-instrument/cover_instrument_location.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff 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

0 commit comments

Comments
 (0)