Skip to content

Commit 482ba29

Browse files
author
Remi Delmas
committed
using the same wrapping approach for enforcement and replacement
1 parent 432444f commit 482ba29

File tree

2 files changed

+195
-69
lines changed

2 files changed

+195
-69
lines changed

src/goto-instrument/contracts/dfcc.cpp

Lines changed: 97 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ Author: Remi Delmas, delmarsd@amazon.com
4747

4848
#include <ansi-c/c_expr.h>
4949
#include <ansi-c/cprover_library.h>
50+
#include <linking/static_lifetime_init.h>
5051
// #include <goto-instrument/loop_utils.h>
5152

5253
#include "instrument_spec_assigns.h"
@@ -472,11 +473,11 @@ void dfcct::transform_goto_model(
472473

473474
// swap and wrap contract-checked functions
474475
for(const auto &entry : check_contracts)
475-
wrap_with_contract_check(entry.first, entry.second);
476+
check_contract(entry.first, entry.second);
476477

477478
// swap and wrap contract-replaced functions
478479
for(const auto &entry : replace_contracts)
479-
wrap_with_contract_abstraction(entry.first, entry.second);
480+
replace_with_contract(entry.first, entry.second);
480481
}
481482

482483
void dfcct::transform_harness_function(const irep_idt &function_id)
@@ -1934,6 +1935,42 @@ void dfcct::instrument_other(
19341935
}
19351936
}
19361937

1938+
symbol_exprt dfcct::add_recursion_tracking_variable(const irep_idt &function_id)
1939+
{
1940+
const auto &function_symbol = get_function_symbol(function_id);
1941+
const irep_idt identifier = id2string(function_id) + "::on_stack";
1942+
symbolt new_symbol;
1943+
new_symbol.name = identifier;
1944+
new_symbol.base_name = identifier;
1945+
new_symbol.pretty_name = identifier;
1946+
new_symbol.type = bool_typet();
1947+
new_symbol.is_static_lifetime = true;
1948+
new_symbol.value = false_exprt();
1949+
new_symbol.mode = function_symbol.mode;
1950+
new_symbol.module = function_symbol.module;
1951+
new_symbol.location = function_symbol.location;
1952+
new_symbol.is_thread_local = true;
1953+
new_symbol.is_lvalue = true;
1954+
1955+
bool failed = goto_model.symbol_table.add(new_symbol);
1956+
CHECK_RETURN(!failed);
1957+
1958+
if(goto_model.goto_functions.function_map.erase(INITIALIZE_FUNCTION) != 0)
1959+
{
1960+
static_lifetime_init(
1961+
goto_model.symbol_table,
1962+
goto_model.symbol_table.lookup_ref(INITIALIZE_FUNCTION).location);
1963+
goto_convert(
1964+
INITIALIZE_FUNCTION,
1965+
goto_model.symbol_table,
1966+
goto_model.goto_functions,
1967+
message_handler);
1968+
goto_model.goto_functions.update();
1969+
}
1970+
1971+
return new_symbol.symbol_expr();
1972+
}
1973+
19371974
void dfcct::wrap_function(
19381975
const irep_idt &function_id,
19391976
const irep_idt &wrapped_function_id)
@@ -2030,33 +2067,81 @@ void dfcct::wrap_function(
20302067
wrapper_fun.body.add(goto_programt::make_end_function(sl));
20312068
}
20322069

2033-
void dfcct::wrap_with_contract_check(
2070+
void dfcct::check_contract(
20342071
const irep_idt &function_id,
20352072
const irep_idt &contract_id)
20362073
{
2037-
2074+
/* Generates this code
2075+
```
2076+
IF on_stack GOTO replace;
2077+
on_stack = true;
2078+
<check_contracting_instructions>;
2079+
on_stack = false;
2080+
GOTO end;
2081+
2082+
replace:
2083+
<add_contract_replacement_instructions>;
2084+
2085+
end:
2086+
END_FUNCTION;
2087+
```
2088+
*/
2089+
irep_idt wrapped_id =
2090+
id2string(function_id) + "_wrapped_for_contract_checking";
2091+
wrap_function(function_id, wrapped_id);
2092+
2093+
goto_programt body;
2094+
2095+
auto on_stack = add_recursion_tracking_variable(wrapped_id);
2096+
2097+
auto recursion_check_goto =
2098+
body.add(goto_programt::make_incomplete_goto(on_stack));
2099+
body.add(goto_programt::make_assignment(on_stack, true_exprt()));
2100+
add_contract_checking_instructions(
2101+
wrapped_id, function_id, contract_id, body);
2102+
body.add(goto_programt::make_assignment(on_stack, false_exprt()));
2103+
2104+
auto goto_end_function = body.add(goto_programt::make_incomplete_goto());
2105+
2106+
auto contract_replacement_label = body.add(goto_programt::make_skip());
2107+
2108+
recursion_check_goto->complete_goto(contract_replacement_label);
2109+
2110+
add_contract_replacement_instructions(function_id, contract_id, body);
2111+
2112+
auto end_function_label = body.add(goto_programt::make_end_function());
2113+
goto_end_function->complete_goto(end_function_label);
2114+
goto_model.goto_functions.function_map.at(function_id).body.swap(body);
20382115
}
20392116

2040-
void dfcct::wrap_with_contract_abstraction(
2117+
void dfcct::replace_with_contract(
20412118
const irep_idt &function_id,
20422119
const irep_idt &contract_id)
20432120
{
2044-
2121+
irep_idt wrapped_id =
2122+
id2string(function_id) + "_wrapped_for_contract_replacement";
2123+
wrap_function(function_id, wrapped_id);
2124+
goto_programt body;
2125+
add_contract_replacement_instructions(function_id, contract_id, body);
2126+
body.add(goto_programt::make_end_function());
2127+
goto_model.goto_functions.function_map.at(function_id).body.swap(body);
20452128
}
20462129

2047-
void dfcct::generate_contract_abstraction_body(
2048-
const irep_idt &wrapped_id,
2130+
void dfcct::add_contract_replacement_instructions(
20492131
const irep_idt &wrapper_id,
2050-
const irep_idt &contract_id)
2132+
const irep_idt &contract_id,
2133+
goto_programt &dest)
20512134
{
2135+
//HERE
20522136
}
20532137

2054-
// HERE
2055-
void dfcct::generate_contract_check_body(
2138+
void dfcct::add_contract_checking_instructions(
20562139
const irep_idt &wrapped_id,
20572140
const irep_idt &wrapper_id,
2058-
const irep_idt &contract_id)
2141+
const irep_idt &contract_id,
2142+
goto_programt &dest)
20592143
{
2144+
//HERE
20602145
}
20612146
// {
20622147
// TODO

src/goto-instrument/contracts/dfcc.h

Lines changed: 98 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,8 @@ class dfcct
219219
/// Adds the given symbol as parameter to the given code_typet.
220220
void add_parameter(const symbolt &symbol, code_typet &code_type);
221221

222-
/// Adds a parameter to the given function
222+
/// Adds a parameter with given `base_name` and `type` to the given
223+
/// `function_id`. Both the symbol and the goto_function are updated.
223224
const symbolt &add_parameter(
224225
const irep_idt &function_id,
225226
const std::string &base_name,
@@ -245,66 +246,15 @@ class dfcct
245246
goto_programt &decl_init,
246247
goto_programt &dead);
247248

248-
/// Wraps the given function_id
249-
/// in a wrapper that checks the given contract_id against the function.
250-
void wrap_with_contract_check(
251-
const irep_idt &function_id,
252-
const irep_idt &contract_id);
253-
254-
/// Genrates the body of the wrapper function as follows:
255-
///
256-
/// ```
257-
/// static _Bool replace_wrapper_by_contract = 0;
258-
///
259-
/// ret_t wrapper(params) {
260-
/// if(replace_wrapper_by_contract) {
261-
/// // replace call with contract
262-
/// return contract::replace(params);
263-
/// } else {
264-
/// // check contract against wrapped function
265-
/// replace_wrapper_by_contract = 1;
266-
/// ret_t ret;
267-
/// // declare history params ...
268-
/// assume(requires);
269-
/// ret = wrapped(params);
270-
/// assert(ensures);
271-
/// replace_wrapper_by_contract = 0;
272-
/// return ret;
273-
/// }
274-
/// }
275-
/// ```
276-
/// \param wrapped_id name of the function that is to be wrapped
277-
/// \param contract_id name of the symbol carrying the contract clauses
278-
/// \param wrapper_id name to use for the wrapper function
279-
void generate_contract_check_body(
280-
const irep_idt &wrapped_id,
281-
const irep_idt &wrapper_id,
282-
const irep_idt &contract_id);
283-
284-
/// Generates the body of the wrapper function as follows:
285-
/// ```
286-
/// ret_t wrapper(params) {
287-
/// return contract::replace(params);
288-
/// }
289-
void wrap_with_contract_abstraction(
290-
const irep_idt &function_id,
291-
const irep_idt &contract_id);
292-
293-
void generate_contract_abstraction_body(
294-
const irep_idt &wrapped_id,
295-
const irep_idt &wrapper_id,
296-
const irep_idt &contract_id);
297-
298-
299249
/// Given a function to wrap `foo` and a new name `wrapped_foo`
300250
///
301251
/// ```
302252
/// ret_t foo(x_t foo::x, y_t foo::y) { foo_body; }
303253
/// ```
304254
///
305-
/// This creates a new entry in the symbol_table for
306-
/// `wrapped_foo` and moves the goto_function `foo_body` under
307-
/// `wrapped_foo` in `function_map`.
255+
/// This method creates a new entry in the symbol_table for
256+
/// `wrapped_foo` and moves the body of the original function, `foo_body`,
257+
/// under `wrapped_foo` in `function_map`.
308258
///
309259
/// The parameter symbols of `wrapped_foo` remain the same as in `foo`:
310260
/// ```
@@ -329,10 +279,101 @@ class dfcct
329279
const irep_idt &wrapped_function_id);
330280

331281

282+
/// Wraps the given function_id
283+
/// in a wrapper that checks the given contract_id against the function.
284+
///
285+
/// ```
286+
/// static bool on_stack = false;
287+
///
288+
/// ret_t foo(params) {
289+
/// IF on_stack GOTO replacement_label;
290+
/// <contract checking instructions>
291+
/// replacement_label;
292+
/// <contract replacement instructions>
293+
/// }
294+
/// ```
295+
void check_contract(
296+
const irep_idt &function_id,
297+
const irep_idt &contract_id);
298+
299+
/// Wraps the given function_id
300+
/// in a wrapper that models contract replacement.
301+
void replace_with_contract(
302+
const irep_idt &function_id,
303+
const irep_idt &contract_id);
304+
305+
306+
/// Adds instruction modeling contract checking, assuming
307+
/// `ret_t wrapper_id(params, __dfcc_set)` receives the instructions.
308+
///
309+
/// \param wrapped_id name of the function that is to be wrapped
310+
/// \param contract_id name of the symbol carrying the contract clauses
311+
/// \param wrapper_id name to use for the wrapper function
312+
/// \param dest goto program where instructions are appended
313+
///
314+
/// The generated instructions:
315+
/// ```
316+
/// DECL __dfcc_set_local: assignable_set_t;
317+
/// CALL assignable_set_create(
318+
/// &__dfcc_set_local, size_hint(contract_id), append_mode = false);
319+
/// CALL contract_id::assigns(params, &_dfcc_set_local);
320+
/// CALL contract_id::frees(params, &_dfcc_set_local);
321+
/// DECL __is_fresh_set: assignable_obj_set_t;
322+
/// CALL obj_set_create(&__is_fresh_set);
323+
/// ASSUME contract::pre(params);
324+
/// DECL hist = ...;
325+
/// CALL ret = wrapped_id(params, &__dfcc_set_local);
326+
/// ASSERT contract::post(params, hist, ret);
327+
/// SET_RETURN_VALUE ret;
328+
/// ```
329+
///
330+
void add_contract_checking_instructions(
331+
const irep_idt &wrapped_id,
332+
const irep_idt &wrapper_id,
333+
const irep_idt &contract_id,
334+
goto_programt& dest);
335+
336+
337+
/// Adds instruction modeling contract replacement, assuming
338+
/// `ret_t wrapper(params, __dfcc_set)` receives the instructions.
339+
///
340+
/// \param contract_id name of the symbol carrying the contract clauses
341+
/// \param wrapper_id name to use for the wrapper function
342+
/// \param dest goto program where instructions are appended
343+
///
344+
/// The generated instructions:
345+
/// ```
346+
/// DECL __dfcc_set_local: assignable_set_t ;
347+
/// CALL assignable_set_create(
348+
/// &__dfcc_set_local, size_hint(contract_id), append_mode = true);
349+
/// CALL contract::assigns(params, &_dfcc_set_local);
350+
/// CALL contract::frees(params, &_dfcc_set_local);
351+
/// ASSERT check_assigns_clause_inclusion(__dfcc_set, &__dfcc_set_local);
352+
/// ASSERT check_frees_clause_inclusion(__dfcc_set, &__dfcc_set_local);
353+
/// DECL __is_fresh_set: assignable_obj_set_t;
354+
/// CALL obj_set_create(&__is_fresh_set);
355+
/// ASSERT contract::pre(params);
356+
/// DECL hist = ...; // snapshot history variables
357+
/// CALL contract::havoc(__dfcc_set_local);
358+
/// CALL ret = nondet();
359+
/// ASSUME contract::post(params, hist, ret);
360+
/// SET_RETURN_VALUE ret;
361+
/// ```
362+
void add_contract_replacement_instructions(
363+
const irep_idt &wrapper_id,
364+
const irep_idt &contract_id,
365+
goto_programt& dest);
366+
367+
/// Adds a global static `function_id::on_stack` for tracking
368+
/// recursive calls to `function_id`.
369+
symbol_exprt add_recursion_tracking_variable(const irep_idt &function_id);
370+
332371
/// Creates a new symbol in the `symbol_table` by cloning
333-
/// the given `function_id` function.
372+
/// the given `function_id` function and transforming the
373+
/// function's name, parameter names, return type and source location
374+
/// using the given functions.
334375
///
335-
/// Also creates a new `goto_function` under the new name in
376+
/// Also creates a new `goto_function` under the transformed name in
336377
/// the `function_map` with new parameters and an empty body.
337378
/// Returns the new symbol.
338379
///

0 commit comments

Comments
 (0)