Skip to content

Commit 1e687f6

Browse files
committed
Library functions: mark them as compiled
When adding library functions to the goto model we no longer need their function bodies as values in the symbol table. Marking them as "compiled" will make sure we don't re-convert them in any subsequent run (e.g., running cbmc after goto-instrument). Doing so would undo any application of "drop-unused-functions." This was most notable with contracts/dynamic frames, where we ended up reporting thousands of properties as "SUCCESS" in library functions that were never actually called. For some contracts examples this now reduces the number of properties reported from over a thousand to tens of properties, and in other cases this made apparent that we were spuriously reporting "SUCCESS" when we never actually invoked those functions in the first place.
1 parent 0760cd7 commit 1e687f6

File tree

9 files changed

+69
-46
lines changed

9 files changed

+69
-46
lines changed

regression/contracts-dfcc/chain.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,5 +58,8 @@ elif echo $args_inst | grep -q -- "--dump-c" ; then
5858

5959
rm "${name}${dfcc_suffix}-mod.c"
6060
fi
61+
if ! echo "${args_cbmc}" | grep -q -- --function ; then
62+
$goto_instrument --drop-unused-functions "${name}${dfcc_suffix}-mod.gb" "${name}${dfcc_suffix}-mod.gb"
63+
fi
6164
$goto_instrument --show-goto-functions "${name}${dfcc_suffix}-mod.gb"
6265
$cbmc "${name}${dfcc_suffix}-mod.gb" ${args_cbmc}

regression/contracts/assigns_enforce_03/main.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
void f2(int *, int *, int *);
2+
void f3(int *, int *, int *);
3+
14
void f1(int *x1, int *y1, int *z1) __CPROVER_assigns(*x1, *y1, *z1)
25
{
36
f2(x1, y1, z1);
@@ -22,6 +25,8 @@ int main()
2225
int q = 2;
2326
int r = 3;
2427
f1(&p, &q, &r);
28+
f2(&p, &q, &r);
29+
f3(&p, &q, &r);
2530

2631
return 0;
2732
}

regression/contracts/assigns_enforce_03/test.desc

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
CORE
22
main.c
33
--enforce-contract f1 --enforce-contract f2 --enforce-contract f3
4-
^\[f1.assigns.\d+\] line 1 Check that \*x1 is valid: SUCCESS$
5-
^\[f1.assigns.\d+\] line 1 Check that \*y1 is valid: SUCCESS$
6-
^\[f1.assigns.\d+\] line 1 Check that \*z1 is valid: SUCCESS$
7-
^\[f2.assigns.\d+\] line 6 Check that \*x2 is valid: SUCCESS$
8-
^\[f2.assigns.\d+\] line 6 Check that \*y2 is valid: SUCCESS$
9-
^\[f2.assigns.\d+\] line 6 Check that \*z2 is valid: SUCCESS$
10-
^\[f3.assigns.\d+\] line 11 Check that \*x3 is valid: SUCCESS$
11-
^\[f3.assigns.\d+\] line 11 Check that \*y3 is valid: SUCCESS$
12-
^\[f3.assigns.\d+\] line 12 Check that \*z3 is valid: SUCCESS$
13-
^\[f3.assigns.\d+\] line 14 Check that \*x3 is assignable: SUCCESS$
14-
^\[f3.assigns.\d+\] line 15 Check that \*y3 is assignable: SUCCESS$
15-
^\[f3.assigns.\d+\] line 16 Check that \*z3 is assignable: SUCCESS$
4+
^\[f1.assigns.\d+\] line 4 Check that \*x1 is valid: SUCCESS$
5+
^\[f1.assigns.\d+\] line 4 Check that \*y1 is valid: SUCCESS$
6+
^\[f1.assigns.\d+\] line 4 Check that \*z1 is valid: SUCCESS$
7+
^\[f2.assigns.\d+\] line 9 Check that \*x2 is valid: SUCCESS$
8+
^\[f2.assigns.\d+\] line 9 Check that \*y2 is valid: SUCCESS$
9+
^\[f2.assigns.\d+\] line 9 Check that \*z2 is valid: SUCCESS$
10+
^\[f3.assigns.\d+\] line 14 Check that \*x3 is valid: SUCCESS$
11+
^\[f3.assigns.\d+\] line 14 Check that \*y3 is valid: SUCCESS$
12+
^\[f3.assigns.\d+\] line 15 Check that \*z3 is valid: SUCCESS$
13+
^\[f3.assigns.\d+\] line 17 Check that \*x3 is assignable: SUCCESS$
14+
^\[f3.assigns.\d+\] line 18 Check that \*y3 is assignable: SUCCESS$
15+
^\[f3.assigns.\d+\] line 19 Check that \*z3 is assignable: SUCCESS$
1616
^VERIFICATION SUCCESSFUL$
1717
^EXIT=0$
1818
^SIGNAL=0$

regression/contracts/chain.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,5 +41,8 @@ elif echo $args_inst | grep -q -- "--dump-c" ; then
4141

4242
rm "${name}-mod.c"
4343
fi
44+
if ! echo "${args_cbmc}" | grep -q -- --function ; then
45+
$goto_instrument --drop-unused-functions "${name}-mod.gb" "${name}-mod.gb"
46+
fi
4447
$goto_instrument --show-goto-functions "${name}-mod.gb"
4548
$cbmc "${name}-mod.gb" ${args_cbmc}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
CORE
2+
main.c
3+
--apply-loop-contracts
4+
^\[ackermann\.\d+\] line 21 Check loop invariant before entry: SUCCESS$
5+
^\[ackermann\.\d+\] line 21 Check that loop invariant is preserved: SUCCESS$
6+
^\[ackermann\.\d+\] line 21 Check decreases clause on loop iteration: SUCCESS$
7+
^\[ackermann.assigns.\d+\] line 29 Check that m is assignable: SUCCESS$
8+
^\[ackermann.assigns.\d+\] line 30 Check that n is assignable: SUCCESS$
9+
^\[ackermann.assigns.\d+\] line 35 Check that m is assignable: SUCCESS$
10+
^\[ackermann.overflow.\d+] line 39 arithmetic overflow on signed \+ in n \+ 1: FAILURE$
11+
^\*\* 1 of \d+ failed
12+
^VERIFICATION FAILED$
13+
^EXIT=10$
14+
^SIGNAL=0$
15+
--
16+
--
17+
It tests whether we can prove (only partially) the termination of the Ackermann
18+
function using a multidimensional decreases clause.
19+
20+
Note that this particular implementation of the Ackermann function contains
21+
both a while-loop and recursion. Therefore, to fully prove the termination of
22+
the Ackermann function, we must prove both
23+
(i) the termination of the while-loop and
24+
(ii) the termination of the recursion.
25+
Because CBMC does not support termination proofs of recursions (yet), we cannot
26+
prove the latter, but the former. Hence, the termination proof in the code is
27+
only "partial."
Lines changed: 4 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,18 @@
11
CORE
22
main.c
3-
--apply-loop-contracts --replace-call-with-contract ackermann
3+
--replace-call-with-contract ackermann
44
^\[ackermann.precondition\.\d+\] line \d+ Check requires clause of ackermann in main: SUCCESS$
5-
^\[ackermann.precondition\.\d+\] line \d+ Check requires clause of ackermann in ackermann: SUCCESS$
6-
^\[ackermann\.\d+\] line 21 Check loop invariant before entry: SUCCESS$
7-
^\[ackermann\.\d+\] line 21 Check that loop invariant is preserved: SUCCESS$
8-
^\[ackermann\.\d+\] line 21 Check decreases clause on loop iteration: SUCCESS$
9-
^\[ackermann.assigns.\d+\] line 29 Check that m is assignable: SUCCESS$
10-
^\[ackermann.assigns.\d+\] line 30 Check that n is assignable: SUCCESS$
11-
^\[ackermann.assigns.\d+\] line 34 Check that n is assignable: SUCCESS$
12-
^\[ackermann.assigns.\d+\] line 35 Check that m is assignable: SUCCESS$
135
^VERIFICATION SUCCESSFUL$
146
^EXIT=0$
157
^SIGNAL=0$
168
--
179
--
18-
It tests whether we can prove (only partially) the termination of the Ackermann
19-
function using a multidimensional decreases clause.
20-
21-
Note that this particular implementation of the Ackermann function contains
22-
both a while-loop and recursion. Therefore, to fully prove the termination of
23-
the Ackermann function, we must prove both
24-
(i) the termination of the while-loop and
25-
(ii) the termination of the recursion.
26-
Because CBMC does not support termination proofs of recursions (yet), we cannot
27-
prove the latter, but the former. Hence, the termination proof in the code is
28-
only "partial."
29-
30-
Furthermore, the Ackermann function has a function contract that the result
10+
The Ackermann function has a function contract that the result
3111
is always non-negative. This post-condition is necessary for establishing
3212
the loop invariant. However, in this test, we do not enforce the function
3313
contract. Instead, we assume that the function contract is correct and use it
34-
(i.e. replace a recursive call of the Ackermann function with its contract).
14+
(i.e. replace a recursive call of the Ackermann function with its contract).
3515

3616
We cannot verify/enforce the function contract of the Ackermann function, since
3717
CBMC does not support function contracts for recursively defined functions.
38-
As of now, CBMC only supports function contracts for non-recursive functions.
18+
As of now, CBMC only supports function contracts for non-recursive functions.

src/ansi-c/goto-conversion/link_to_library.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,26 +41,32 @@ add_one_function(
4141
// convert to CFG
4242
if(
4343
library_model.symbol_table.symbols.find(missing_function) !=
44-
library_model.symbol_table.symbols.end())
44+
library_model.symbol_table.symbols.end() &&
45+
library_model.symbol_table.lookup_ref(missing_function).value.is_not_nil())
4546
{
4647
goto_convert(
4748
missing_function,
4849
library_model.symbol_table,
4950
library_model.goto_functions,
5051
message_handler);
52+
library_model.symbol_table.get_writeable_ref(missing_function)
53+
.set_compiled();
5154
}
5255
// We might need a function that's outside our own library, but brought in via
5356
// some header file included by the library. Those functions already exist in
5457
// goto_model.symbol_table, but haven't been converted just yet.
5558
else if(
5659
goto_model.symbol_table.symbols.find(missing_function) !=
57-
goto_model.symbol_table.symbols.end())
60+
goto_model.symbol_table.symbols.end() &&
61+
goto_model.symbol_table.lookup_ref(missing_function).value.is_not_nil() &&
62+
!goto_model.symbol_table.lookup_ref(missing_function).is_compiled())
5863
{
5964
goto_convert(
6065
missing_function,
6166
goto_model.symbol_table,
6267
library_model.goto_functions,
6368
message_handler);
69+
goto_model.symbol_table.get_writeable_ref(missing_function).set_compiled();
6470
}
6571

6672
// check whether additional initialization may be required

src/goto-instrument/contracts/dynamic-frames/dfcc_library.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,7 @@ void dfcc_libraryt::load(std::set<irep_idt> &to_instrument)
326326
{
327327
goto_convert(
328328
id, goto_model.symbol_table, goto_model.goto_functions, message_handler);
329+
goto_model.symbol_table.get_writeable_ref(id).set_compiled();
329330
}
330331

331332
// check that all symbols have a goto_implementation

src/goto-synthesizer/cegis_verifier.cpp

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -546,12 +546,8 @@ cext cegis_verifiert::build_cex(
546546

547547
void cegis_verifiert::restore_functions()
548548
{
549-
for(const auto &fun_entry : goto_model.goto_functions.function_map)
550-
{
551-
irep_idt fun_name = fun_entry.first;
552-
goto_model.goto_functions.function_map[fun_name].body.swap(
553-
original_functions[fun_name]);
554-
}
549+
for(auto &[fun_name, orig_fun_body] : original_functions)
550+
goto_model.goto_functions.function_map[fun_name].body.swap(orig_fun_body);
555551
}
556552

557553
std::optional<cext> cegis_verifiert::verify()
@@ -569,10 +565,12 @@ std::optional<cext> cegis_verifiert::verify()
569565
// 3. construct the formatted counterexample from the violated property and
570566
// its trace.
571567

572-
// Store the original functions. We will restore them after the verification.
568+
// Store the original functions when they have a body (library functions might
569+
// not yet have one). We will restore them after the verification.
573570
for(const auto &fun_entry : goto_model.goto_functions.function_map)
574571
{
575-
original_functions[fun_entry.first].copy_from(fun_entry.second.body);
572+
if(fun_entry.second.body_available())
573+
original_functions[fun_entry.first].copy_from(fun_entry.second.body);
576574
}
577575

578576
// Annotate the candidates to the goto_model for checking.

0 commit comments

Comments
 (0)