Skip to content

Commit 905167f

Browse files
author
Remi Delmas
committed
CONTRACTS: insert reachability canary asssertions
When a GOTO function has no body, insert a canary assertion to make the analysis fail in case the function is reachable. Add `assert(false)` bodies for front-end functions `__CPROVER_assignable`, `__CPROVER_object_whole`, `__CPROVER_object_from`, `__CPROVER_object_upto` to make the analysis fail when they are used outside of contract clauses and are hence not remapped to their library implementation.
1 parent c3b72e4 commit 905167f

File tree

8 files changed

+67
-35
lines changed

8 files changed

+67
-35
lines changed

regression/contracts-dfcc/assigns_replace_02/main.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#include <assert.h>
22

3-
void foo(int *x, int *y) __CPROVER_assigns(*x)
3+
void foo(int *x) __CPROVER_assigns(*x)
44
{
55
*x = 7;
66
}
@@ -9,7 +9,7 @@ int main()
99
{
1010
int n;
1111
int m = 4;
12-
bar(&n);
12+
foo(&n);
1313
assert(m == 4);
1414

1515
return 0;

regression/contracts-dfcc/cprover-assignable-fail/test.desc

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@ CALL __CPROVER_object_whole
55
CALL __CPROVER_object_upto
66
CALL __CPROVER_object_from
77
CALL __CPROVER_assignable
8-
^\[__CPROVER_object_(assignable|from|upto|whole).*.\d+\] Built-in __CPROVER_object_(assignable|from|upto|whole) should not be called after contracts transformation: FAILURE$
8+
^\[__CPROVER_assignable.assertion.\d+\].*undefined function should be unreachable: FAILURE$
9+
^\[__CPROVER_object_from.assertion.\d+\].*undefined function should be unreachable: FAILURE$
10+
^\[__CPROVER_object_upto.assertion.\d+\].*undefined function should be unreachable: FAILURE$
11+
^\[__CPROVER_object_whole.assertion.\d+\].*undefined function should be unreachable: FAILURE$
912
^\[my_write_set.assertion.\d+\] .* target null or writable: FAILURE$
1013
^VERIFICATION FAILED$
1114
^EXIT=10$
@@ -18,5 +21,7 @@ This test checks that:
1821
__CPROVER_object_upto are supported;
1922
- GOTO conversion preserves calls to __CPROVER_object_whole,
2023
__CPROVER_object_upto, __CPROVER_object_from;
24+
- reachability assertions are inserted in front-end functions and allow to
25+
detect when front-end functions are used outside of contracts clauses;
2126
- GOTO conversion translates __CPROVER_typed_target to __CPROVER_assignable;
2227
- user-defined checks embedded in `my_write_set` persist after conversion.

regression/contracts-dfcc/cprover-assignable-pass/test.desc

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@ CALL __CPROVER_object_whole
55
CALL __CPROVER_object_upto
66
CALL __CPROVER_object_from
77
CALL __CPROVER_assignable
8-
^\[__CPROVER_object_(assignable|from|upto|whole).*.\d+\] Built-in __CPROVER_object_(assignable|from|upto|whole) should not be called after contracts transformation: FAILURE$
8+
^\[__CPROVER_assignable.assertion.\d+\].*undefined function should be unreachable: FAILURE$
9+
^\[__CPROVER_object_from.assertion.\d+\].*undefined function should be unreachable: FAILURE$
10+
^\[__CPROVER_object_upto.assertion.\d+\].*undefined function should be unreachable: FAILURE$
11+
^\[__CPROVER_object_whole.assertion.\d+\].*undefined function should be unreachable: FAILURE$
912
^\[my_write_set.assertion.\d+\] .* target null or writable: SUCCESS$
1013
^EXIT=10$
1114
^SIGNAL=0$
@@ -14,8 +17,11 @@ CALL __CPROVER_assignable
1417
CALL __CPROVER_typed_target
1518
--
1619
This test checks that:
17-
- built-in __CPROVER_assignable_t functions are supported;
20+
- built-in __CPROVER_assignable, __CPROVER_object_from, __CPROVER_object_upto,
21+
__CPROVER_object_whole functions are supported in the front-end;
1822
- GOTO conversion preserves calls to __CPROVER_object_whole,
1923
__CPROVER_object_upto, __CPROVER_object_from;
24+
- reachability assertions are inserted in front-end functions and allow to
25+
detect when front-end functions are used outside of contracts clauses;
2026
- GOTO conversion translates __CPROVER_typed_target to __CPROVER_assignable;
2127
- user-defined checks embedded in `my_write_set` persist after conversion.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
int foo(int);
2+
3+
int bar(int i) __CPROVER_requires(i > 0)
4+
__CPROVER_ensures(__CPROVER_return_value > 0)
5+
{
6+
return foo(i);
7+
}
8+
9+
int main()
10+
{
11+
int i;
12+
bar(i);
13+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
CORE
2+
main.c
3+
--dfcc main --enforce-contract bar
4+
^\[foo.assertion.\d+\] line 1 undefined function should be unreachable: FAILURE$
5+
^VERIFICATION FAILED$
6+
^EXIT=10$
7+
^SIGNAL=0$
8+
--
9+
--
10+
This test checks that functions without bodies result in analysis failures.

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

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,11 @@ Author: Remi Delmas, [email protected]
2222
#include <goto-programs/remove_skip.h>
2323

2424
#include <ansi-c/c_expr.h>
25+
#include <ansi-c/c_object_factory_parameters.h>
2526
#include <goto-instrument/contracts/cfg_info.h>
2627
#include <goto-instrument/contracts/contracts.h>
2728
#include <goto-instrument/contracts/utils.h>
29+
#include <goto-instrument/generate_function_bodies.h>
2830
#include <langapi/language_util.h>
2931

3032
#include "dfcc_is_freeable.h"
@@ -33,6 +35,8 @@ Author: Remi Delmas, [email protected]
3335
#include "dfcc_obeys_contract.h"
3436
#include "dfcc_utils.h"
3537

38+
#include <memory>
39+
3640
std::set<irep_idt> dfcc_instrumentt::function_cache;
3741

3842
dfcc_instrumentt::dfcc_instrumentt(
@@ -340,10 +344,13 @@ void dfcc_instrumentt::instrument_function_body(
340344

341345
if(!goto_function.body_available())
342346
{
343-
log.warning() << "DFCC instrumentation: '" << function_id
344-
<< "' body is not available. Results may be unsound if the "
345-
"actual function has side effects."
346-
<< messaget::eom;
347+
// generate a default body `assert(false);assume(false);`
348+
std::string options = "assert-false-assume-false";
349+
c_object_factory_parameterst object_factory_params;
350+
auto generate_function_bodies = generate_function_bodies_factory(
351+
options, object_factory_params, goto_model.symbol_table, message_handler);
352+
generate_function_bodies->generate_function_body(
353+
goto_function, goto_model.symbol_table, function_id);
347354
return;
348355
}
349356

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

Lines changed: 14 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ Author: Remi Delmas, [email protected]
2323
#include <goto-programs/goto_model.h>
2424

2525
#include <ansi-c/c_expr.h>
26+
#include <ansi-c/c_object_factory_parameters.h>
2627
#include <ansi-c/cprover_library.h>
28+
#include <goto-instrument/generate_function_bodies.h>
2729
#include <goto-instrument/unwind.h>
2830
#include <goto-instrument/unwindset.h>
2931
#include <linking/static_lifetime_init.h>
@@ -488,32 +490,21 @@ void dfcc_libraryt::fix_malloc_free_calls()
488490

489491
void dfcc_libraryt::inhibit_front_end_builtins()
490492
{
493+
// not using assume-false in order not to hinder coverage
494+
std::string options = "assert-false";
495+
c_object_factory_parameterst object_factory_params;
496+
auto generate_function_bodies = generate_function_bodies_factory(
497+
options, object_factory_params, goto_model.symbol_table, message_handler);
491498
for(const auto &it : dfcc_hook)
492499
{
493-
const auto &fid = it.first;
494-
if(goto_model.symbol_table.has_symbol(fid))
500+
const auto &function_id = it.first;
501+
if(goto_model.symbol_table.has_symbol(function_id))
495502
{
496-
// make sure parameter symbols exist
497-
utils.fix_parameters_symbols(fid);
498-
499-
// create fatal assertion code block as body
500-
source_locationt sl;
501-
sl.set_function(fid);
502-
sl.set_file("<built-in-additions>");
503-
sl.set_property_class("sanity_check");
504-
sl.set_comment(
505-
"Built-in " + id2string(fid) +
506-
" should not be called after contracts transformation");
507-
auto block = create_fatal_assertion(false_exprt(), sl);
508-
auto &symbol = goto_model.symbol_table.get_writeable_ref(fid);
509-
symbol.value = block;
510-
511-
// convert the function
512-
goto_convert(
513-
fid,
514-
goto_model.symbol_table,
515-
goto_model.goto_functions,
516-
message_handler);
503+
auto &goto_function =
504+
goto_model.goto_functions.function_map.at(function_id);
505+
506+
generate_function_bodies->generate_function_body(
507+
goto_function, goto_model.symbol_table, function_id);
517508
}
518509
}
519510
}

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -233,14 +233,14 @@ class dfcc_libraryt
233233
/// \param contract_assigns_size_hint size of the assigns clause being checked
234234
void specialize(const std::size_t contract_assigns_size_hint);
235235

236-
/// Adds an ASSERT(false) body to all front-end functions
236+
/// Adds an ASSERT(false);ASSUME(false); body to all front-end functions
237237
/// __CPROVER_object_whole
238238
/// __CPROVER_object_upto
239239
/// __CPROVER_object_from
240240
/// __CPROVER_assignable
241241
/// __CPROVER_freeable
242-
/// To make sure they cannot be used in a proof unexpectedly
243-
/// without causing verification errors.
242+
/// An error will be triggered in case calls to these functions occur outside
243+
/// of a contrat clause.
244244
void inhibit_front_end_builtins();
245245

246246
/// Sets the given hide flag on all instructions of all library functions

0 commit comments

Comments
 (0)