Skip to content

Commit bbafecd

Browse files
author
Aalok Thakkar
committed
Added support for loop_entry history variable.
1. Created a new predicate __CPROVER_loop_entry which can be used in the loop invariant to keep track of the value of a variable at the start of the loop. 2. Modified the code contract to support this history variable.
1 parent 25ed175 commit bbafecd

File tree

4 files changed

+19
-4
lines changed

4 files changed

+19
-4
lines changed

src/ansi-c/c_typecheck_expr.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2647,7 +2647,8 @@ exprt c_typecheck_baset::do_special_functions(
26472647

26482648
return std::move(ok_expr);
26492649
}
2650-
else if(identifier == CPROVER_PREFIX "old")
2650+
else if(identifier == CPROVER_PREFIX "old" ||
2651+
identifier == CPROVER_PREFIX "loop_entry")
26512652
{
26522653
if(expr.arguments().size() != 1)
26532654
{

src/ansi-c/cprover_builtin_headers.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ void __CPROVER_fence(const char *kind, ...);
3737
// contract-related functions
3838
__CPROVER_bool __CPROVER_is_fresh(const void *mem, __CPROVER_size_t size);
3939
void __CPROVER_old(const void *);
40+
void __CPROVER_loop_entry(const void *);
4041

4142
// pointers
4243
__CPROVER_size_t __CPROVER_POINTER_OBJECT(const void *);

src/goto-instrument/contracts/contracts.cpp

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,17 @@ void code_contractst::check_apply_loop_contracts(
174174
return invariant_copy;
175175
};
176176

177+
// Process "loop_entry" history variables
178+
179+
std::map<exprt, exprt> parameter2history;
180+
goto_programt history;
181+
182+
// Find and replace "loop_entry" expression in the "invariant" variable
183+
replace_old_parameter(invariant, parameter2history, loop_head->source_location, mode, history);
184+
185+
// Create 'loop_entry' history variables
186+
insert_before_swap_and_advance(havoc_code, loop_head, history);
187+
177188
// Generate: assert(invariant) just before the loop
178189
// We use a block scope to create a temporary assertion,
179190
// and immediately convert it to goto instructions.
@@ -387,10 +398,11 @@ void code_contractst::replace_old_parameter(
387398
replace_old_parameter(op, parameter2history, location, mode, history);
388399
}
389400

390-
if(expr.id() == ID_old)
401+
if(expr.id() == ID_old ||
402+
expr.id() == ID_loop_entry)
391403
{
392404
DATA_INVARIANT(
393-
expr.operands().size() == 1, CPROVER_PREFIX "old must have one operand");
405+
expr.operands().size() == 1, "history variable must have one operand");
394406

395407
const auto &parameter = to_old_expr(expr).expression();
396408

@@ -427,7 +439,7 @@ void code_contractst::replace_old_parameter(
427439
}
428440
else
429441
{
430-
log.error() << CPROVER_PREFIX "old does not currently support "
442+
log.error() << "history variables do not currently support "
431443
<< parameter.id() << " expressions." << messaget::eom;
432444
throw 0;
433445
}

src/util/irep_ids.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -691,6 +691,7 @@ IREP_ID_ONE(r_ok)
691691
IREP_ID_ONE(w_ok)
692692
IREP_ID_ONE(rw_ok)
693693
IREP_ID_ONE(old)
694+
IREP_ID_ONE(loop_entry)
694695
IREP_ID_ONE(super_class)
695696
IREP_ID_ONE(exceptions_thrown_list)
696697
IREP_ID_TWO(C_java_method_type, #java_method_type)

0 commit comments

Comments
 (0)