Skip to content

Commit 3f20567

Browse files
committed
Handling function pointers in contracts instrumentation
During instrumentation for enforcing/replacing function contracts, all calls to function pointers were not handled. We now consider that a function call might be a dereference and properly handle it during instrumentation. Signed-off-by: Felipe R. Monteiro <[email protected]>
1 parent 556b432 commit 3f20567

File tree

3 files changed

+65
-8
lines changed

3 files changed

+65
-8
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#include <assert.h>
2+
#include <stdlib.h>
3+
4+
static int add_operator(const int *a, const int *b)
5+
{
6+
return (*a + *b);
7+
}
8+
9+
// clang-format off
10+
int foo(int *x, int *y)
11+
__CPROVER_requires(x != NULL && y != NULL)
12+
__CPROVER_ensures(__CPROVER_return_value == 10)
13+
// clang-format on
14+
{
15+
int (*sum)(const int *, const int *) = add_operator;
16+
return sum(x, y);
17+
}
18+
19+
int main()
20+
{
21+
int x = 5;
22+
int y = 5;
23+
assert(foo(&x, &y) == 10);
24+
return 0;
25+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
CORE
2+
main.c
3+
--enforce-all-contracts
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
\[postcondition.\d+\] file main.c line \d+ Check ensures clause: SUCCESS
7+
\[foo.\d+\] line \d+ Check that sum is assignable: SUCCESS
8+
\[main.assertion.\d+\] line \d+ assertion foo\(\&x, \&y\) \=\= 10: SUCCESS
9+
^VERIFICATION SUCCESSFUL$
10+
--
11+
--
12+
Checks whether function contracts are properly propagated to function pointers.

src/goto-instrument/code_contracts.cpp

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -649,8 +649,16 @@ void code_contractst::instrument_call_statement(
649649
"a function call");
650650

651651
code_function_callt call = instruction_iterator->get_function_call();
652-
const irep_idt &called_name =
653-
to_symbol_expr(call.function()).get_identifier();
652+
irep_idt called_name;
653+
if(call.function().id() == ID_dereference)
654+
{
655+
called_name = to_symbol_expr(to_dereference_expr(call.function()).pointer())
656+
.get_identifier();
657+
}
658+
else
659+
{
660+
called_name = to_symbol_expr(call.function()).get_identifier();
661+
}
654662

655663
if(called_name == "malloc")
656664
{
@@ -699,12 +707,15 @@ void code_contractst::instrument_call_statement(
699707
++instruction_iterator;
700708
}
701709

702-
PRECONDITION(call.function().id() == ID_symbol);
703710
const symbolt &called_symbol = ns.lookup(called_name);
704-
const code_typet &called_type = to_code_type(called_symbol.type);
705-
711+
// Called symbol might be a function pointer.
712+
const typet &called_symbol_type = (called_symbol.type.id() == ID_pointer)
713+
? called_symbol.type.subtype()
714+
: called_symbol.type;
706715
exprt called_assigns =
707-
to_code_with_contract_type(called_symbol.type).assigns();
716+
to_code_with_contract_type(called_symbol_type).assigns();
717+
const code_typet &called_type = to_code_type(called_symbol_type);
718+
708719
if(called_assigns.is_not_nil())
709720
{
710721
replace_symbolt replace_formal_params;
@@ -753,8 +764,17 @@ bool code_contractst::check_for_looped_mallocs(const goto_programt &program)
753764
if(instruction.is_function_call())
754765
{
755766
code_function_callt call = instruction.get_function_call();
756-
const irep_idt &called_name =
757-
to_symbol_expr(call.function()).get_identifier();
767+
irep_idt called_name;
768+
if(call.function().id() == ID_dereference)
769+
{
770+
called_name =
771+
to_symbol_expr(to_dereference_expr(call.function()).pointer())
772+
.get_identifier();
773+
}
774+
else
775+
{
776+
called_name = to_symbol_expr(call.function()).get_identifier();
777+
}
758778

759779
if(called_name == "malloc")
760780
{

0 commit comments

Comments
 (0)