@@ -321,14 +321,11 @@ void code_contractst::check_apply_loop_contracts(
321321 optionalt<cfg_infot> cfg_empty_info;
322322
323323 // Perform write set instrumentation on the entire loop.
324- check_frame_conditions (
325- function_name,
324+ instrument_spec_assigns.instrument_instructions (
326325 goto_function.body ,
327326 loop_head,
328327 loop_end,
329- instrument_spec_assigns,
330- // do not skip checks on function parameter assignments
331- skipt::DontSkip,
328+ skip_function_paramst::NO,
332329 // do not use CFG info for now
333330 cfg_empty_info);
334331
@@ -960,68 +957,6 @@ goto_functionst &code_contractst::get_goto_functions()
960957 return goto_functions;
961958}
962959
963- void code_contractst::instrument_assign_statement (
964- goto_programt::targett &instruction_it,
965- goto_programt &program,
966- instrument_spec_assignst &instrument_spec_assigns,
967- optionalt<cfg_infot> &cfg_info_opt)
968- {
969- auto lhs = instruction_it->assign_lhs ();
970- lhs.add_source_location () = instruction_it->source_location ();
971- goto_programt payload;
972- instrument_spec_assigns.check_inclusion_assignment (
973- lhs, cfg_info_opt, payload);
974- insert_before_swap_and_advance (program, instruction_it, payload);
975- }
976-
977- void code_contractst::instrument_call_statement (
978- goto_programt::targett &instruction_it,
979- const irep_idt &function,
980- goto_programt &body,
981- instrument_spec_assignst &instrument_spec_assigns,
982- optionalt<cfg_infot> &cfg_info_opt)
983- {
984- INVARIANT (
985- instruction_it->is_function_call (),
986- " The first argument of instrument_call_statement should always be "
987- " a function call" );
988-
989- const auto &callee_name =
990- to_symbol_expr (instruction_it->call_function ()).get_identifier ();
991-
992- if (callee_name == " malloc" )
993- {
994- const auto &function_call =
995- to_code_function_call (instruction_it->get_code ());
996- if (function_call.lhs ().is_not_nil ())
997- {
998- // grab the returned pointer from malloc
999- auto object = pointer_object (function_call.lhs ());
1000- object.add_source_location () = function_call.source_location ();
1001- // move past the call and then insert the CAR
1002- instruction_it++;
1003- goto_programt payload;
1004- instrument_spec_assigns.track_heap_allocated (object, payload);
1005- insert_before_swap_and_advance (body, instruction_it, payload);
1006- // since CAR was inserted *after* the malloc call,
1007- // move the instruction pointer backward,
1008- // because the caller increments it in a `for` loop
1009- instruction_it--;
1010- }
1011- }
1012- else if (callee_name == " free" )
1013- {
1014- const auto &ptr = instruction_it->call_arguments ().front ();
1015- auto object = pointer_object (ptr);
1016- object.add_source_location () = instruction_it->source_location ();
1017- goto_programt payload;
1018- instrument_spec_assigns
1019- .check_inclusion_heap_allocated_and_invalidate_aliases (
1020- object, cfg_info_opt, payload);
1021- insert_before_swap_and_advance (body, instruction_it, payload);
1022- }
1023- }
1024-
1025960bool code_contractst::check_for_looped_mallocs (const goto_programt &program)
1026961{
1027962 // Collect all GOTOs and mallocs
@@ -1101,9 +1036,9 @@ bool code_contractst::check_frame_conditions_function(const irep_idt &function)
11011036 auto &function_body = function_obj->second .body ;
11021037
11031038 // Get assigns clause for function
1104- const symbolt &function_sybmol = ns.lookup (function);
1039+ const symbolt &function_symbol = ns.lookup (function);
11051040 const auto &function_with_contract =
1106- to_code_with_contract_type (function_sybmol .type );
1041+ to_code_with_contract_type (function_symbol .type );
11071042
11081043 instrument_spec_assignst instrument_spec_assigns (
11091044 function, goto_functions, symbol_table, log.get_message_handler ());
@@ -1158,7 +1093,7 @@ bool code_contractst::check_frame_conditions_function(const irep_idt &function)
11581093
11591094 // Track formal parameters
11601095 goto_programt snapshot_function_parameters;
1161- for (const auto ¶m : to_code_type (function_sybmol .type ).parameters ())
1096+ for (const auto ¶m : to_code_type (function_symbol .type ).parameters ())
11621097 {
11631098 goto_programt payload;
11641099 instrument_spec_assigns.track_stack_allocated (
@@ -1170,184 +1105,16 @@ bool code_contractst::check_frame_conditions_function(const irep_idt &function)
11701105 goto_functions.update ();
11711106
11721107 // Insert write set inclusion checks.
1173- check_frame_conditions (
1174- function,
1108+ instrument_spec_assigns.instrument_instructions (
11751109 function_body,
11761110 instruction_it,
11771111 function_body.instructions .end (),
1178- instrument_spec_assigns,
1179- // skip checks on function parameter assignments
1180- skipt::Skip,
1112+ skip_function_paramst::YES,
11811113 cfg_info_opt);
11821114
11831115 return false ;
11841116}
11851117
1186- // / Returns true iff the target instruction is tagged with a
1187- // / 'CONTRACT_PRAGMA_DISABLE_ASSIGNS_CHECK' pragma.
1188- bool has_disable_assigns_check_pragma (
1189- const goto_programt::const_targett &target)
1190- {
1191- const auto &pragmas = target->source_location ().get_pragmas ();
1192- return pragmas.find (CONTRACT_PRAGMA_DISABLE_ASSIGNS_CHECK) != pragmas.end ();
1193- }
1194-
1195- // / Returns true iff an `ASSIGN lhs := rhs` instruction must be instrumented.
1196- bool must_check_assign (
1197- const goto_programt::const_targett &target,
1198- code_contractst::skipt skip_parameter_assigns,
1199- const namespacet ns,
1200- const optionalt<cfg_infot> cfg_info_opt)
1201- {
1202- if (
1203- const auto &symbol_expr =
1204- expr_try_dynamic_cast<symbol_exprt>(target->assign_lhs ()))
1205- {
1206- if (
1207- skip_parameter_assigns == code_contractst::skipt::DontSkip &&
1208- ns.lookup (symbol_expr->get_identifier ()).is_parameter )
1209- return true ;
1210-
1211- if (cfg_info_opt.has_value ())
1212- return !cfg_info_opt.value ().is_local (symbol_expr->get_identifier ());
1213- }
1214-
1215- return true ;
1216- }
1217-
1218- // / Returns true iff a `DECL x` must be added to the local write set.
1219- // /
1220- // / A variable is called 'dirty' if its address gets taken at some point in
1221- // / the program.
1222- // /
1223- // / Assuming the goto program is obtained from a structured C program that
1224- // / passed C compiler checks, non-dirty variables can only be assigned to
1225- // / directly by name, cannot escape their lexical scope, and are always safe
1226- // / to assign. Hence, we only track dirty variables in the write set.
1227- bool must_track_decl (
1228- const goto_programt::const_targett &target,
1229- const optionalt<cfg_infot> &cfg_info_opt)
1230- {
1231- if (cfg_info_opt.has_value ())
1232- return cfg_info_opt.value ().is_not_local_or_dirty_local (
1233- target->decl_symbol ().get_identifier ());
1234-
1235- // Unless proved non-dirty by the CFG analysis we assume it is dirty.
1236- return true ;
1237- }
1238-
1239- // / Returns true iff a `DEAD x` must be processed to upate the local write set.
1240- // / The conditions are the same than for tracking a `DECL x` instruction.
1241- bool must_track_dead (
1242- const goto_programt::const_targett &target,
1243- const optionalt<cfg_infot> &cfg_info_opt)
1244- {
1245- // Unless proved non-dirty by the CFG analysis we assume it is dirty.
1246- if (!cfg_info_opt.has_value ())
1247- return true ;
1248-
1249- return cfg_info_opt.value ().is_not_local_or_dirty_local (
1250- target->dead_symbol ().get_identifier ());
1251- }
1252-
1253- void code_contractst::check_frame_conditions (
1254- const irep_idt &function,
1255- goto_programt &body,
1256- goto_programt::targett instruction_it,
1257- const goto_programt::targett &instruction_end,
1258- instrument_spec_assignst &instrument_spec_assigns,
1259- skipt skip_parameter_assigns,
1260- optionalt<cfg_infot> &cfg_info_opt)
1261- {
1262- while (instruction_it != instruction_end)
1263- {
1264- // Skip instructions marked as disabled for assigns clause checking
1265- if (has_disable_assigns_check_pragma (instruction_it))
1266- {
1267- instruction_it++;
1268- if (cfg_info_opt.has_value ())
1269- cfg_info_opt.value ().step ();
1270- continue ;
1271- }
1272-
1273- // Do not instrument this instruction again in the future,
1274- // since we are going to instrument it now below.
1275- add_pragma_disable_assigns_check (*instruction_it);
1276-
1277- if (
1278- instruction_it->is_decl () &&
1279- must_track_decl (instruction_it, cfg_info_opt))
1280- {
1281- // grab the declared symbol
1282- const auto &decl_symbol = instruction_it->decl_symbol ();
1283- // move past the call and then insert the CAR
1284- instruction_it++;
1285- goto_programt payload;
1286- instrument_spec_assigns.track_stack_allocated (decl_symbol, payload);
1287- insert_before_swap_and_advance (body, instruction_it, payload);
1288- // since CAR was inserted *after* the DECL instruction,
1289- // move the instruction pointer backward,
1290- // because the loop step takes care of the increment
1291- instruction_it--;
1292- }
1293- else if (
1294- instruction_it->is_assign () &&
1295- must_check_assign (
1296- instruction_it, skip_parameter_assigns, ns, cfg_info_opt))
1297- {
1298- instrument_assign_statement (
1299- instruction_it, body, instrument_spec_assigns, cfg_info_opt);
1300- }
1301- else if (instruction_it->is_function_call ())
1302- {
1303- instrument_call_statement (
1304- instruction_it, function, body, instrument_spec_assigns, cfg_info_opt);
1305- }
1306- else if (
1307- instruction_it->is_dead () &&
1308- must_track_dead (instruction_it, cfg_info_opt))
1309- {
1310- const auto &symbol = instruction_it->dead_symbol ();
1311- if (instrument_spec_assigns.stack_allocated_is_tracked (symbol))
1312- {
1313- goto_programt payload;
1314- instrument_spec_assigns.invalidate_stack_allocated (symbol, payload);
1315- insert_before_swap_and_advance (body, instruction_it, payload);
1316- }
1317- else
1318- {
1319- // For loops, the loop_head appears after the DECL of counters,
1320- // and any other temporaries introduced during "initialization".
1321- // However, they go `DEAD` (possible conditionally) inside the loop,
1322- // in presence of return statements.
1323- // Notice that for them those variables be writable,
1324- // they must appear as assigns targets anyway,
1325- // but their DECL statements are outside of the loop.
1326- log.warning () << " Found a `DEAD` variable " << symbol.get_identifier ()
1327- << " without corresponding `DECL`, at: "
1328- << instruction_it->source_location () << messaget::eom;
1329- }
1330- }
1331- else if (
1332- instruction_it->is_other () &&
1333- instruction_it->get_other ().get_statement () == ID_havoc_object)
1334- {
1335- auto havoc_argument = instruction_it->get_other ().operands ().front ();
1336- auto havoc_object = pointer_object (havoc_argument);
1337- havoc_object.add_source_location () = instruction_it->source_location ();
1338- goto_programt payload;
1339- instrument_spec_assigns.check_inclusion_assignment (
1340- havoc_object, cfg_info_opt, payload);
1341- insert_before_swap_and_advance (body, instruction_it, payload);
1342- }
1343-
1344- // Move to the next instruction
1345- instruction_it++;
1346- if (cfg_info_opt.has_value ())
1347- cfg_info_opt.value ().step ();
1348- }
1349- }
1350-
13511118bool code_contractst::enforce_contract (const irep_idt &function)
13521119{
13531120 // Add statements to the source function
0 commit comments