Skip to content

Commit c0d742b

Browse files
authored
Merge pull request #6352 from feliperodri/frame-condition-havoc-fix
Check frame conditions before __CPROVER_havoc_object
2 parents c67c340 + 7075866 commit c0d742b

File tree

4 files changed

+69
-27
lines changed

4 files changed

+69
-27
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#include <assert.h>
2+
#include <stdlib.h>
3+
4+
int x = 0;
5+
6+
void foo(int *y) __CPROVER_assigns()
7+
{
8+
__CPROVER_havoc_object(y);
9+
x = 2;
10+
}
11+
12+
int main()
13+
{
14+
int *y = malloc(sizeof(*y));
15+
*y = 0;
16+
foo(y);
17+
assert(x == 2);
18+
return 0;
19+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
CORE
2+
main.c
3+
--enforce-all-contracts
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
^\[foo.\d+\] line \d+ Check that \*y is assignable: FAILURE$
7+
^\[foo.\d+\] line \d+ Check that x is assignable: FAILURE$
8+
^VERIFICATION FAILED$
9+
--
10+
--
11+
Checks whether contract enforcement works with __CPROVER_havoc_object.

src/goto-instrument/contracts/contracts.cpp

Lines changed: 31 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -715,14 +715,7 @@ void code_contractst::instrument_assign_statement(
715715
assigns_clause.add_to_local_write_set(lhs);
716716
}
717717

718-
goto_programt alias_assertion;
719-
alias_assertion.add(goto_programt::make_assertion(
720-
assigns_clause.generate_containment_check(lhs),
721-
instruction_iterator->source_location));
722-
alias_assertion.instructions.back().source_location.set_comment(
723-
"Check that " + from_expr(ns, lhs.id(), lhs) + " is assignable");
724-
insert_before_swap_and_advance(
725-
program, instruction_iterator, alias_assertion);
718+
add_containment_check(program, assigns_clause, instruction_iterator, lhs);
726719
}
727720

728721
void code_contractst::instrument_call_statement(
@@ -766,37 +759,24 @@ void code_contractst::instrument_call_statement(
766759
}
767760
else if(called_name == "free")
768761
{
769-
goto_programt alias_assertion;
770762
const exprt &lhs_dereference = dereference_exprt(
771763
to_typecast_expr(instruction_iterator->call_arguments().front()).op());
772-
alias_assertion.add(goto_programt::make_assertion(
773-
assigns_clause.generate_containment_check(lhs_dereference),
774-
instruction_iterator->source_location));
775-
alias_assertion.instructions.back().source_location.set_comment(
776-
"Check that " + from_expr(ns, lhs_dereference.id(), lhs_dereference) +
777-
" is assignable");
764+
add_containment_check(
765+
program, assigns_clause, instruction_iterator, lhs_dereference);
778766
assigns_clause.remove_from_local_write_set(lhs_dereference);
779767
assigns_clause.remove_from_global_write_set(lhs_dereference);
780-
insert_before_swap_and_advance(
781-
program, instruction_iterator, alias_assertion);
782768
return;
783769
}
784770

785771
if(
786772
instruction_iterator->call_lhs().is_not_nil() &&
787773
instruction_iterator->call_lhs().id() == ID_symbol)
788774
{
789-
const auto alias_expr = assigns_clause.generate_containment_check(
775+
add_containment_check(
776+
program,
777+
assigns_clause,
778+
instruction_iterator,
790779
instruction_iterator->call_lhs());
791-
792-
goto_programt alias_assertion;
793-
alias_assertion.add(goto_programt::make_assertion(
794-
alias_expr, instruction_iterator->source_location));
795-
alias_assertion.instructions.back().source_location.set_comment(
796-
"Check that " + from_expr(ns, alias_expr.id(), alias_expr) +
797-
" is assignable");
798-
insert_before_swap_and_advance(
799-
program, instruction_iterator, alias_assertion);
800780
}
801781

802782
const symbolt &called_symbol = ns.lookup(called_name);
@@ -972,9 +952,33 @@ void code_contractst::check_frame_conditions(
972952
{
973953
assigns.remove_from_local_write_set(instruction_it->get_dead().symbol());
974954
}
955+
else if(
956+
instruction_it->is_other() &&
957+
instruction_it->get_other().get_statement() == ID_havoc_object)
958+
{
959+
const exprt &havoc_argument = dereference_exprt(
960+
to_typecast_expr(instruction_it->get_other().operands().front()).op());
961+
add_containment_check(program, assigns, instruction_it, havoc_argument);
962+
assigns.remove_from_local_write_set(havoc_argument);
963+
assigns.remove_from_global_write_set(havoc_argument);
964+
}
975965
}
976966
}
977967

968+
void code_contractst::add_containment_check(
969+
goto_programt &program,
970+
const assigns_clauset &assigns,
971+
goto_programt::instructionst::iterator &instruction_it,
972+
const exprt &expr)
973+
{
974+
goto_programt assertion;
975+
assertion.add(goto_programt::make_assertion(
976+
assigns.generate_containment_check(expr), instruction_it->source_location));
977+
assertion.instructions.back().source_location.set_comment(
978+
"Check that " + from_expr(ns, expr.id(), expr) + " is assignable");
979+
insert_before_swap_and_advance(program, instruction_it, assertion);
980+
}
981+
978982
bool code_contractst::enforce_contract(const irep_idt &function)
979983
{
980984
// Add statements to the source function

src/goto-instrument/contracts/contracts.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,14 @@ class code_contractst
152152
/// assigned memory is within the assignable memory frame.
153153
void check_frame_conditions(goto_programt &, assigns_clauset &);
154154

155+
/// Inserts an assertion into the goto program to ensure that
156+
/// an expression is within the assignable memory frame.
157+
void add_containment_check(
158+
goto_programt &,
159+
const assigns_clauset &,
160+
goto_programt::instructionst::iterator &,
161+
const exprt &);
162+
155163
/// Check if there are any malloc statements which may be repeated because of
156164
/// a goto statement that jumps back.
157165
bool check_for_looped_mallocs(const goto_programt &program);

0 commit comments

Comments
 (0)