@@ -141,9 +141,6 @@ void code_contractst::check_apply_loop_contracts(
141
141
generated_code,
142
142
ID_loop_entry);
143
143
144
- // Create 'loop_entry' history variables
145
- insert_before_swap_and_advance (goto_function.body , loop_head, generated_code);
146
-
147
144
// Generate: assert(invariant) just before the loop
148
145
// We use a block scope to create a temporary assertion,
149
146
// and immediately convert it to goto instructions.
@@ -155,6 +152,14 @@ void code_contractst::check_apply_loop_contracts(
155
152
" Check loop invariant before entry" );
156
153
}
157
154
155
+ // Add 'loop_entry' history variables and base case assertion.
156
+ // These variables are local and thus
157
+ // need not be checked against the enclosing scope's write set.
158
+ insert_before_swap_and_advance (
159
+ goto_function.body ,
160
+ loop_head,
161
+ add_pragma_disable_assigns_check (generated_code));
162
+
158
163
// havoc the variables that may be modified
159
164
modifiest modifies;
160
165
if (assigns.is_nil ())
@@ -177,7 +182,8 @@ void code_contractst::check_apply_loop_contracts(
177
182
for (const auto &target : assigns.operands ())
178
183
modifies.insert (target);
179
184
180
- // create snapshots of the CARs -- must be done before havocing
185
+ // Create snapshots of write set CARs.
186
+ // This must be done before havocing the write set.
181
187
for (const auto &car : loop_assigns.get_write_set ())
182
188
{
183
189
auto snapshot_instructions = car.generate_snapshot_instructions ();
@@ -189,7 +195,17 @@ void code_contractst::check_apply_loop_contracts(
189
195
havoc_assigns_targetst havoc_gen (modifies, ns);
190
196
havoc_gen.append_full_havoc_code (
191
197
loop_head->source_location (), generated_code);
192
- insert_before_swap_and_advance (goto_function.body , loop_head, generated_code);
198
+
199
+ // Add the havocing code, but only check against the enclosing scope's
200
+ // write set if it was manually specified.
201
+ if (assigns.is_nil ())
202
+ insert_before_swap_and_advance (
203
+ goto_function.body ,
204
+ loop_head,
205
+ add_pragma_disable_assigns_check (generated_code));
206
+ else
207
+ insert_before_swap_and_advance (
208
+ goto_function.body , loop_head, generated_code);
193
209
194
210
// Generate: assume(invariant) just after havocing
195
211
// We use a block scope to create a temporary assumption,
@@ -744,7 +760,6 @@ void code_contractst::instrument_assign_statement(
744
760
instruction_it->is_assign (),
745
761
" The first instruction of instrument_assign_statement should always be"
746
762
" an assignment" );
747
-
748
763
add_inclusion_check (
749
764
program, assigns_clause, instruction_it, instruction_it->assign_lhs ());
750
765
}
@@ -834,7 +849,9 @@ void code_contractst::instrument_call_statement(
834
849
835
850
alias_checking_instructions.destructive_append (skip_program);
836
851
insert_before_swap_and_advance (
837
- body, instruction_it, alias_checking_instructions);
852
+ body,
853
+ instruction_it,
854
+ add_pragma_disable_assigns_check (alias_checking_instructions));
838
855
839
856
// move past the call and then insert the invalidation instructions
840
857
instruction_it++;
@@ -866,7 +883,9 @@ void code_contractst::instrument_call_statement(
866
883
867
884
invalidation_instructions.destructive_append (skip_program);
868
885
insert_before_swap_and_advance (
869
- body, instruction_it, invalidation_instructions);
886
+ body,
887
+ instruction_it,
888
+ add_pragma_disable_assigns_check (invalidation_instructions));
870
889
871
890
instruction_it--;
872
891
}
@@ -1003,6 +1022,14 @@ void code_contractst::check_frame_conditions(
1003
1022
1004
1023
for (; instruction_it != instruction_end; ++instruction_it)
1005
1024
{
1025
+ const auto &pragmas = instruction_it->source_location ().get_pragmas ();
1026
+ if (pragmas.find (CONTRACT_PRAGMA_DISABLE_ASSIGNS_CHECK) != pragmas.end ())
1027
+ continue ;
1028
+
1029
+ // Do not instrument this instruction again in the future,
1030
+ // since we are going to instrument it now below.
1031
+ add_pragma_disable_assigns_check (*instruction_it);
1032
+
1006
1033
if (instruction_it->is_decl ())
1007
1034
{
1008
1035
// grab the declared symbol
0 commit comments