Skip to content

Commit 7894298

Browse files
author
Aalok Thakkar
committed
update
1 parent 3c66465 commit 7894298

File tree

6 files changed

+89
-6
lines changed

6 files changed

+89
-6
lines changed

src/ansi-c/c_typecheck_base.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ class c_typecheck_baset:
144144
virtual void typecheck_while(code_whilet &code);
145145
virtual void typecheck_dowhile(code_dowhilet &code);
146146
virtual void typecheck_start_thread(codet &code);
147+
virtual void typecheck_spec_assigns(codet &code);
147148
virtual void typecheck_spec_loop_invariant(codet &code);
148149
virtual void typecheck_spec_decreases(codet &code);
149150

src/ansi-c/c_typecheck_code.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,7 @@ void c_typecheck_baset::typecheck_for(codet &code)
484484
typecheck_code(code); // recursive call
485485
}
486486

487+
typecheck_spec_assigns(code);
487488
typecheck_spec_loop_invariant(code);
488489
typecheck_spec_decreases(code);
489490
}
@@ -773,6 +774,7 @@ void c_typecheck_baset::typecheck_while(code_whilet &code)
773774
break_is_allowed=old_break_is_allowed;
774775
continue_is_allowed=old_continue_is_allowed;
775776

777+
typecheck_spec_assigns(code);
776778
typecheck_spec_loop_invariant(code);
777779
typecheck_spec_decreases(code);
778780
}
@@ -807,10 +809,29 @@ void c_typecheck_baset::typecheck_dowhile(code_dowhilet &code)
807809
break_is_allowed=old_break_is_allowed;
808810
continue_is_allowed=old_continue_is_allowed;
809811

812+
typecheck_spec_assigns(code);
810813
typecheck_spec_loop_invariant(code);
811814
typecheck_spec_decreases(code);
812815
}
813816

817+
void c_typecheck_baset::typecheck_spec_assigns(codet &code)
818+
{
819+
if(code.find(ID_C_spec_assigns).is_not_nil())
820+
{
821+
for(const exprt &operand : static_cast<exprt &>(code.add(ID_C_spec_assigns)).operands())
822+
{
823+
if(
824+
operand.id() != ID_symbol && operand.id() != ID_ptrmember &&
825+
operand.id() != ID_member && operand.id() != ID_dereference)
826+
{
827+
error().source_location = code.source_location();
828+
error() << "illegal target in assigns clause" << eom;
829+
throw 0;
830+
}
831+
}
832+
}
833+
}
834+
814835
void c_typecheck_baset::typecheck_spec_loop_invariant(codet &code)
815836
{
816837
if(code.find(ID_C_spec_loop_invariant).is_not_nil())

src/ansi-c/parser.y

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2453,6 +2453,9 @@ iteration_statement:
24532453
statement($$, ID_while);
24542454
parser_stack($$).add_to_operands(std::move(parser_stack($3)), std::move(parser_stack($8)));
24552455

2456+
if(!parser_stack($4).is_not_nil())
2457+
parser_stack($$).add(ID_C_spec_assigns).swap(parser_stack($4));
2458+
24562459
if(!parser_stack($6).operands().empty())
24572460
static_cast<exprt &>(parser_stack($$).add(ID_C_spec_loop_invariant)).operands().swap(parser_stack($6).operands());
24582461

@@ -2468,6 +2471,9 @@ iteration_statement:
24682471
statement($$, ID_dowhile);
24692472
parser_stack($$).add_to_operands(std::move(parser_stack($5)), std::move(parser_stack($2)));
24702473

2474+
if(!parser_stack($7).is_not_nil())
2475+
parser_stack($$).add(ID_C_spec_assigns).swap(parser_stack($7));
2476+
24712477
if(!parser_stack($8).operands().empty())
24722478
static_cast<exprt &>(parser_stack($$).add(ID_C_spec_loop_invariant)).operands().swap(parser_stack($8).operands());
24732479

@@ -2499,6 +2505,9 @@ iteration_statement:
24992505
mto($$, $7);
25002506
mto($$, $12);
25012507

2508+
if(!parser_stack($9).is_not_nil())
2509+
parser_stack($$).add(ID_C_spec_assigns).swap(parser_stack($9));
2510+
25022511
if(!parser_stack($10).operands().empty())
25032512
static_cast<exprt &>(parser_stack($$).add(ID_C_spec_loop_invariant)).operands().swap(parser_stack($10).operands());
25042513

src/goto-instrument/contracts/assigns.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,11 @@ goto_programt assigns_clauset::havoc_code(
238238
return havoc_statements;
239239
}
240240

241+
std::vector<assigns_clause_targett *> assigns_clauset::getTargets()
242+
{
243+
return targets;
244+
}
245+
241246
exprt assigns_clauset::alias_expression(const exprt &lhs)
242247
{
243248
if(targets.empty())

src/goto-instrument/contracts/assigns.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ class assigns_clauset
7373
irep_idt function_name,
7474
irep_idt language_mode);
7575
exprt alias_expression(const exprt &lhs);
76+
std::vector<assigns_clause_targett *> getTargets();
7677

7778
exprt compatible_expression(const assigns_clauset &called_assigns);
7879

src/goto-instrument/contracts/contracts.cpp

Lines changed: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,10 @@ void code_contractst::check_apply_loop_contracts(
7070
t->location_number > loop_end->location_number)
7171
loop_end = t;
7272

73-
// see whether we have an invariant and a decreases clause
73+
// see whether we have an assigns clause, an invariant and a decreases clause
74+
75+
exprt assigns = static_cast<const exprt &>(
76+
loop_end->get_condition().find(ID_C_spec_assigns));
7477
exprt invariant = static_cast<const exprt &>(
7578
loop_end->get_condition().find(ID_C_spec_loop_invariant));
7679
exprt decreases_clause = static_cast<const exprt &>(
@@ -119,12 +122,57 @@ void code_contractst::check_apply_loop_contracts(
119122
// assume(false);
120123
// E: ...
121124

122-
// find out what can get changed in the loop
125+
// Check that the assigns clause for loop is compatible
126+
// with the assigns clause for the calling function.
127+
128+
assigns_clauset assigns_clause(assigns, *this, mode, log);
129+
130+
if(assigns.is_not_nil())
131+
{
132+
// extract the assigns clause of the function:
133+
const symbolt &function_symbol = ns.lookup(function_name);
134+
const auto &code_type = to_code_with_contract_type(function_symbol.type);
135+
exprt function_assigns = code_type.assigns();
136+
137+
auto instruction_iterator = loop_head;
138+
139+
if(function_assigns.is_not_nil())
140+
{
141+
// check compatibility of assigns clause with the called function
142+
assigns_clauset function_assigns_clause(function_assigns, *this, function_name, log);
143+
exprt compatible = assigns_clause.compatible_expression(function_assigns_clause);
144+
goto_programt alias_assertion;
145+
alias_assertion.add(goto_programt::make_assertion(
146+
compatible, instruction_iterator->source_location));
147+
alias_assertion.instructions.back().source_location.set_comment(
148+
"Check compatibility of assigns clause with the called function");
149+
goto_function.body.insert_before_swap(instruction_iterator, alias_assertion);
150+
++instruction_iterator;
151+
}
152+
}
153+
154+
// Identify the variables to havoc.
123155
modifiest modifies;
124-
get_modifies(local_may_alias, loop, modifies);
125156

157+
if(assigns.is_not_nil())
158+
{
159+
// If there is an assigns clause, identify the variables in the assigns clause.
160+
for(auto assigns_clause_target : assigns_clause.getTargets()){
161+
modifies.insert(assigns_clause_target->get_direct_pointer());
162+
}
163+
} else
164+
{
165+
throw std::invalid_argument( "assigns is nil" );
166+
// If there is no assigns clause, find out what can get changed in the loop.
167+
get_modifies(local_may_alias, loop, modifies);
168+
}
169+
126170
// build the havocking code
127171
goto_programt havoc_code;
172+
build_havoc_code(loop_head, modifies, havoc_code);
173+
174+
// Insert assertions at assignment
175+
// check_frame_conditions(havoc_code, ns.lookup(function_name));
128176

129177
// process quantified variables correctly (introduce a fresh temporary)
130178
// and return a copy of the invariant
@@ -135,6 +183,7 @@ void code_contractst::check_apply_loop_contracts(
135183
replace(invariant_copy);
136184
return invariant_copy;
137185
};
186+
138187

139188
// Generate: assert(invariant) just before the loop
140189
// We use a block scope to create a temporary assertion,
@@ -147,9 +196,6 @@ void code_contractst::check_apply_loop_contracts(
147196
"Check loop invariant before entry");
148197
}
149198

150-
// havoc variables being written to
151-
build_havoc_code(loop_head, modifies, havoc_code);
152-
153199
// Generate: assume(invariant) just after havocing
154200
// We use a block scope to create a temporary assumption,
155201
// and immediately convert it to goto instructions.

0 commit comments

Comments
 (0)