Skip to content

Commit d761684

Browse files
author
Remi Delmas
committed
CONTRACTS: improved initialisation method for statics
1 parent f121748 commit d761684

File tree

7 files changed

+127
-109
lines changed

7 files changed

+127
-109
lines changed

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

Lines changed: 85 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -30,19 +30,26 @@ Author: Remi Delmas, [email protected]
3030
#include <goto-programs/goto_functions.h>
3131
#include <goto-programs/goto_inline.h>
3232
#include <goto-programs/goto_model.h>
33+
#include <goto-programs/initialize_goto_model.h>
3334
#include <goto-programs/link_to_library.h>
3435
#include <goto-programs/remove_skip.h>
3536
#include <goto-programs/remove_unused_functions.h>
3637

38+
#include <ansi-c/ansi_c_entry_point.h>
3739
#include <ansi-c/c_expr.h>
40+
#include <ansi-c/c_object_factory_parameters.h>
3841
#include <ansi-c/cprover_library.h>
3942
#include <goto-instrument/contracts/cfg_info.h>
4043
#include <goto-instrument/contracts/instrument_spec_assigns.h>
4144
#include <goto-instrument/contracts/utils.h>
4245
#include <goto-instrument/nondet_static.h>
46+
#include <langapi/language.h>
47+
#include <langapi/language_file.h>
48+
#include <langapi/mode.h>
4349
#include <linking/static_lifetime_init.h>
4450

4551
void dfcc(
52+
const optionst &options,
4653
goto_modelt &goto_model,
4754
const irep_idt &harness_id,
4855
const std::set<irep_idt> &to_check,
@@ -60,7 +67,7 @@ void dfcc(
6067
for(const auto &function_id : to_replace)
6168
to_replace_map.insert({function_id, function_id});
6269

63-
dfcct{goto_model, message_handler}.transform_goto_model(
70+
dfcct{options, goto_model, message_handler}.transform_goto_model(
6471
harness_id,
6572
to_check_map,
6673
allow_recursive_calls,
@@ -70,6 +77,7 @@ void dfcc(
7077
}
7178

7279
void dfcc(
80+
const optionst &options,
7381
goto_modelt &goto_model,
7482
const irep_idt &harness_id,
7583
const std::map<irep_idt, irep_idt> &to_check,
@@ -79,7 +87,7 @@ void dfcc(
7987
const std::set<std::string> &to_exclude_from_nondet_static,
8088
message_handlert &message_handler)
8189
{
82-
dfcct{goto_model, message_handler}.transform_goto_model(
90+
dfcct{options, goto_model, message_handler}.transform_goto_model(
8391
harness_id,
8492
to_check,
8593
allow_recursive_calls,
@@ -90,8 +98,12 @@ void dfcc(
9098

9199
std::map<irep_idt, irep_idt> dfcct::wrapped_functions_cache;
92100

93-
dfcct::dfcct(goto_modelt &goto_model, message_handlert &message_handler)
94-
: goto_model(goto_model),
101+
dfcct::dfcct(
102+
const optionst &options,
103+
goto_modelt &goto_model,
104+
message_handlert &message_handler)
105+
: options(options),
106+
goto_model(goto_model),
95107
message_handler(message_handler),
96108
log(message_handler),
97109
utils(goto_model, message_handler),
@@ -126,26 +138,6 @@ void dfcct::check_transform_goto_model_preconditions(
126138
const bool apply_loop_contracts,
127139
const std::set<std::string> &to_exclude_from_nondet_static)
128140
{
129-
// TODO reactivate this once I understand how entry points work
130-
// Check that the goto_model entry point matches the given harness_id
131-
// if(!config.main.has_value())
132-
// {
133-
// log.error() << "dfcct::transform_goto_model: no entry point found in the"
134-
// "goto model, expected '"
135-
// << harness_id << "', aborting contracts transformations."
136-
// << messaget::eom;
137-
// throw invalid_input_exceptiont(msg);
138-
// }
139-
140-
// if(config.main.value() != harness_id)
141-
// {
142-
// log.error() << "dfcct::transform_goto_model: entry point '"
143-
// << config.main.value()
144-
// << "' differs from given harness function '" << harness_id
145-
// << "', aborting contracts transformations." << messaget::eom;
146-
// throw invalid_input_exceptiont(msg);
147-
// }
148-
149141
// check there is at most one function to check
150142
PRECONDITION_WITH_DIAGNOSTICS(
151143
to_check.size() <= 1,
@@ -266,14 +258,6 @@ void dfcct::transform_goto_model(
266258
link_to_library(
267259
goto_model, log.get_message_handler(), cprover_c_library_factory);
268260

269-
// Make all statics nondet. This needs to be done before starting the program
270-
// transformation since the instrumentation adds static variables
271-
// which must keep their initial values to function as intended.
272-
log.status()
273-
<< "Adding nondeterministic initialization of static/global variables."
274-
<< messaget::eom;
275-
nondet_static(goto_model, to_exclude_from_nondet_static);
276-
277261
// partition the set of functions of the goto_model
278262
std::set<irep_idt> pure_contract_symbols;
279263
std::set<irep_idt> other_symbols;
@@ -439,8 +423,74 @@ void dfcct::transform_goto_model(
439423
instrument.get_instrumented_functions(instrumented_functions);
440424
swap_and_wrap.get_swapped_functions(instrumented_functions);
441425

442-
// update statics and static function maps
443-
log.status() << "Updating CPROVER init function" << messaget::eom;
444-
library.create_initialize_function(instrumented_functions);
426+
// Re-initialise the GOTO model.
427+
//
428+
// The new entry point must be the proof harness function specified for
429+
// instrumentation.
430+
//
431+
// The "initialize" (aka INITIALIZE_FUNCTION) is the function that assigns
432+
// initial values to all statics of the model;
433+
//
434+
// The initialize function must do the following:
435+
// - assign a nondet value to all statics of the user program
436+
// - assign the specified initial value to all instrumentation statics
437+
// - add an entry in the static unbounded map of instrumented functions
438+
// for each instrumented function
439+
//
440+
// A call to `nondet_static` will re-generate the initialize function with
441+
// nondet values. The intrumentation statics will not get nondet initialised
442+
// by virtue of being tagged with ID_C_no_nondet_initialization.
443+
//
444+
// However, nondet_static expects instructions to be either function calls
445+
// or assignments with a symbol_exprt LHS.
446+
// Since entries for the instrumented function maps are not symbol_exprts but
447+
// index_exprts they need to be moved to the harness function.
448+
//
449+
// The "start" function (aka goto_functionst::entry_point()) is the
450+
// function from which SymEx starts.
451+
//
452+
// The start function must do the following:
453+
// - call the initialize function,
454+
// - generate nondet values for the arguments of the proof harness function
455+
// - call the harness function with said nondet arguments
456+
//
457+
// All of which can be done using a call to `generate_ansi_c_start_function`,
458+
// assuming the initialize function is already available in the symbol table.
459+
//
460+
// So we do the following:
461+
// - regenerate the "initialize" function
462+
// - call nondet_static
463+
// - add extra instructions at the end of the harness function for the
464+
// instrumented functions map
465+
// - call generate_ansi_c_start_function
466+
467+
// Make all user-defined statics nondet.
468+
// Other statics added by the instrumentation will be unaffected because they
469+
// are tagged with ID_C_no_nondet_initialization when created
470+
471+
// Update statics and static function maps
472+
log.status() << "Updating init function" << messaget::eom;
473+
utils.create_initialize_function();
474+
goto_model.goto_functions.update();
475+
nondet_static(goto_model, to_exclude_from_nondet_static);
476+
477+
// Initialize the map of instrumented functions by adding extra instructions
478+
// to the harness function
479+
auto &init_function = goto_model.goto_functions.function_map[harness_id];
480+
auto &body = init_function.body;
481+
auto begin = body.instructions.begin();
482+
goto_programt payload;
483+
library.add_instrumented_functions_map_init_instructions(
484+
instrumented_functions, begin->source_location(), payload);
485+
body.destructive_insert(begin, payload);
486+
487+
// Define harness as the entry point, overriding any preexisting one.
488+
log.status() << "Setting entry point to " << harness_id << messaget::eom;
489+
generate_ansi_c_start_function(
490+
utils.get_function_symbol(harness_id),
491+
goto_model.symbol_table,
492+
message_handler,
493+
c_object_factory_parameterst(options));
494+
445495
goto_model.goto_functions.update();
446496
}

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

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ class message_handlert;
5252
class symbolt;
5353
class conditional_target_group_exprt;
5454
class cfg_infot;
55+
class optionst;
5556

5657
#define FLAG_DFCC "dfcc"
5758
#define OPT_DFCC "(" FLAG_DFCC "):"
@@ -78,6 +79,8 @@ class cfg_infot;
7879
/// \pre This function requires that the contract associated to function `foo`
7980
/// exists in the symbol table as symbol `contract::foo`.
8081
///
82+
/// \param options CLI options (used to lookup options for language config when
83+
/// re-defining the model's entry point)
8184
/// \param goto_model GOTO model to transform
8285
/// \param harness_id proof harness name, must be the entry point of the model
8386
/// \param to_check set of functions to check against their contract
@@ -89,6 +92,7 @@ class cfg_infot;
8992
/// static program symbols.
9093
/// \param message_handler used for debug/warning/error messages
9194
void dfcc(
95+
const optionst &options,
9296
goto_modelt &goto_model,
9397
const irep_idt &harness_id,
9498
const std::set<irep_idt> &to_check,
@@ -106,6 +110,8 @@ void dfcc(
106110
/// When checking function `foo` against contract `bar`, we require the
107111
/// actual contract symbol to exist as `contract::bar` in the symbol table.
108112
///
113+
/// \param options CLI options (used to lookup options for language config when
114+
/// re-defining the model's entry point)
109115
/// \param goto_model GOTO model to transform
110116
/// \param harness_id Proof harness name, must be the entry point of the model
111117
/// \param to_check functions-to-contract mapping for contract checking
@@ -117,6 +123,7 @@ void dfcc(
117123
/// static program symbols.
118124
/// \param message_handler used for debug/warning/error messages
119125
void dfcc(
126+
const optionst &options,
120127
goto_modelt &goto_model,
121128
const irep_idt &harness_id,
122129
const std::map<irep_idt, irep_idt> &to_check,
@@ -132,9 +139,14 @@ class dfcct
132139
{
133140
public:
134141
/// Class constructor
142+
/// \param options CLI options (used to lookup options for language config
143+
/// when re-defining the model's entry point)
135144
/// \param goto_model GOTO model to transform
136145
/// \param message_handler used for debug/warning/error messages
137-
dfcct(goto_modelt &goto_model, message_handlert &message_handler);
146+
dfcct(
147+
const optionst &options,
148+
goto_modelt &goto_model,
149+
message_handlert &message_handler);
138150

139151
/// Applies function contracts and loop contracts transformation to GOTO model
140152
/// using the dynamic frame condition checking approach.
@@ -178,6 +190,7 @@ class dfcct
178190
const std::set<std::string> &to_exclude_from_nondet_static);
179191

180192
protected:
193+
const optionst &options;
181194
goto_modelt &goto_model;
182195
message_handlert &message_handler;
183196
messaget log;

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

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -833,9 +833,6 @@ void dfcc_instrumentt::instrument_assign(
833833
}
834834
}
835835

836-
#if 0
837-
// TODO re-enable once we can have nondet-static with with arbitrary LHS
838-
// expressions in the INITIALIZE_FUNCTION function
839836
void dfcc_instrumentt::instrument_fptr_call_instruction_dynamic_lookup(
840837
const exprt &write_set,
841838
goto_programt::targett &target,
@@ -864,7 +861,7 @@ void dfcc_instrumentt::instrument_fptr_call_instruction_dynamic_lookup(
864861
: address_of_exprt(callf));
865862
auto index_expr = index_exprt(
866863
library.get_instrumented_functions_map_symbol().symbol_expr(), object_id);
867-
auto cond = notequal_exprt(index_expr, from_integer(1, c_bool_typet(8)));
864+
auto cond = notequal_exprt(index_expr, from_integer(1, unsigned_char_type()));
868865
goto_programt payload;
869866
auto goto_no_inst =
870867
payload.add(goto_programt::make_incomplete_goto(cond, target_location));
@@ -885,7 +882,7 @@ void dfcc_instrumentt::instrument_fptr_call_instruction_dynamic_lookup(
885882
target->turn_into_skip();
886883
insert_before_swap_and_advance(goto_program, target, payload);
887884
}
888-
#endif
885+
889886
void dfcc_instrumentt::instrument_call_instruction(
890887
const exprt &write_set,
891888
goto_programt::targett &target,
@@ -907,11 +904,11 @@ void dfcc_instrumentt::instrument_call_instruction(
907904
}
908905
else
909906
{
910-
// this is a function pointer call.
911-
// pass write set argument
912-
target->call_arguments().push_back(write_set);
913-
// TODO use instrument_fptr_call_instruction_dynamic_lookup once symex
914-
// is able to dispatch function pointers internally
907+
// This is a function pointer call. We insert a dynamic lookup into the
908+
// map of instrumented functions to determine if the target function is
909+
// able to accept a write set parameter.
910+
instrument_fptr_call_instruction_dynamic_lookup(
911+
write_set, target, goto_program);
915912
}
916913
}
917914
}

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -308,18 +308,18 @@ class dfcc_instrumentt
308308
goto_programt::targett &target,
309309
goto_programt &goto_program);
310310

311-
// TODO re-enable once we can have nondet-static with with arbitrary LHS
312-
// expressions in the INITIALIZE_FUNCTION function
313-
#if 0
314-
/// do pass the extra write set parameter only to function pointers that point
315-
/// to instrumented functions that can effectively accept it.
311+
/// Before calling a function pointer, performs a dynamic lookup into
312+
/// the map of instrumented function provided by
313+
/// \ref dfcc_libraryt.get_instrumented_functions_map_symbol,
314+
/// and passes the write_set parameter to the funciton pointer only if
315+
/// it points to a function known to be instrumented and hence able to accept
316+
/// this parameter.
316317
/// \pre \p target points to a `CALL` instruction where the function
317318
/// expression is not a \ref symbol_exprt.
318319
void instrument_fptr_call_instruction_dynamic_lookup(
319320
const exprt &write_set,
320321
goto_programt::targett &target,
321322
goto_programt &goto_program);
322-
#endif
323323

324324
/// Inserts deallocation checks and a write set update before a call
325325
/// to the __CPROVER_deallocate function.

0 commit comments

Comments
 (0)