Skip to content

Commit 9b19704

Browse files
authored
Merge pull request #7487 from qinheping/goto-synthesizer
CONTRACTS: Avoid skipping transformed loop with jumps to the loop head
2 parents e0b348e + 5f87252 commit 9b19704

File tree

5 files changed

+75
-3
lines changed

5 files changed

+75
-3
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
int main()
2+
{
3+
int x;
4+
goto label;
5+
x = 2;
6+
label:
7+
while(x < 5)
8+
__CPROVER_loop_invariant(x <= 5)
9+
{
10+
x++;
11+
}
12+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
CORE
2+
main.c
3+
--apply-loop-contracts
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^\[main\.\d+\] .* Check loop invariant before entry: SUCCESS$
7+
^\[main\.\d+\] .* Check that loop invariant is preserved: SUCCESS$
8+
^\[main.assigns.\d+\] .* Check that x is assignable: SUCCESS$
9+
^VERIFICATION SUCCESSFUL$
10+
--
11+
--
12+
Checks transformed loop won't be skipped by a jump to the loop head.

src/goto-instrument/contracts/contracts.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -890,6 +890,17 @@ void code_contractst::apply_loop_contract(
890890
throw 0;
891891
}
892892

893+
// After loop-contract instrumentation, jumps to the `loop_head` will skip
894+
// some instrumented instructions. So we want to make sure that there is
895+
// only one jump targeting `loop_head` from `loop_end` before loop-contract
896+
// instrumentation.
897+
// Add a skip before `loop_head` and let all jumps (except for the
898+
// `loop_end`) that target to the `loop_head` target to the skip
899+
// instead.
900+
insert_before_and_update_jumps(
901+
goto_function.body, loop_head, goto_programt::make_skip());
902+
loop_end->set_target(loop_head);
903+
893904
exprt assigns_clause =
894905
static_cast<const exprt &>(loop_end->condition().find(ID_C_spec_assigns));
895906
exprt invariant = static_cast<const exprt &>(

src/goto-instrument/contracts/utils.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,19 @@ void insert_before_swap_and_advance(
154154
std::advance(target, offset);
155155
}
156156

157+
void insert_before_and_update_jumps(
158+
goto_programt &destination,
159+
goto_programt::targett &target,
160+
const goto_programt::instructiont &i)
161+
{
162+
const auto new_target = destination.insert_before(target, i);
163+
for(auto it : target->incoming_edges)
164+
{
165+
if(it->is_goto())
166+
it->set_target(new_target);
167+
}
168+
}
169+
157170
const symbolt &new_tmp_symbol(
158171
const typet &type,
159172
const source_locationt &location,

src/goto-instrument/contracts/utils.h

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@ Date: September 2021
1111
#ifndef CPROVER_GOTO_INSTRUMENT_CONTRACTS_UTILS_H
1212
#define CPROVER_GOTO_INSTRUMENT_CONTRACTS_UTILS_H
1313

14-
#include <vector>
14+
#include <goto-programs/goto_convert_class.h>
1515

1616
#include <goto-instrument/havoc_utils.h>
1717

18-
#include <goto-programs/goto_convert_class.h>
18+
#include <vector>
1919

2020
#define IN_BASE_CASE "__in_base_case"
2121
#define ENTERED_LOOP "__entered_loop"
@@ -110,6 +110,30 @@ void insert_before_swap_and_advance(
110110
goto_programt::targett &target,
111111
goto_programt &payload);
112112

113+
/// \brief Insert a goto instruction before a target instruction iterator
114+
/// and update targets of all jumps that points to the iterator to
115+
/// jumping to the inserted instruction. This method is intended
116+
/// to keep external instruction::targett stable, i.e. they will
117+
/// still point to the same instruction after inserting the new one
118+
///
119+
/// This function inserts a instruction `i` into a destination program
120+
/// `destination` immediately before a specified instruction iterator `target`.
121+
/// After insertion, update all jumps that pointing to `target` to jumping to
122+
/// `i` instead.
123+
///
124+
/// Different from `insert_before_swap_and_advance`, this function doesn't
125+
/// invalidate the iterator `target` after insertion. That is, `target` and
126+
/// all other instruction iterators same as `target` will still point to the
127+
/// same instruction after insertion.
128+
///
129+
/// \param destination: The destination program for inserting the `i`.
130+
/// \param target: The instruction iterator at which to insert the `i`.
131+
/// \param i: The goto instruction to be inserted into the `destination`.
132+
void insert_before_and_update_jumps(
133+
goto_programt &destination,
134+
goto_programt::targett &target,
135+
const goto_programt::instructiont &i);
136+
113137
/// \brief Adds a fresh and uniquely named symbol to the symbol table.
114138
///
115139
/// \param type: The type of the new symbol.
@@ -192,7 +216,7 @@ void add_quantified_variable(
192216
const irep_idt &mode);
193217

194218
/// This function recursively identifies the "old" expressions within expr
195-
/// and replaces them with correspoding history variables.
219+
/// and replaces them with corresponding history variables.
196220
void replace_history_parameter(
197221
symbol_table_baset &symbol_table,
198222
exprt &expr,

0 commit comments

Comments
 (0)