@@ -321,14 +321,11 @@ void code_contractst::check_apply_loop_contracts(
321
321
optionalt<cfg_infot> cfg_empty_info;
322
322
323
323
// Perform write set instrumentation on the entire loop.
324
- check_frame_conditions (
325
- function_name,
324
+ instrument_spec_assigns.instrument_instructions (
326
325
goto_function.body ,
327
326
loop_head,
328
327
loop_end,
329
- instrument_spec_assigns,
330
- // do not skip checks on function parameter assignments
331
- skipt::DontSkip,
328
+ skip_function_paramst::NO,
332
329
// do not use CFG info for now
333
330
cfg_empty_info);
334
331
@@ -960,68 +957,6 @@ goto_functionst &code_contractst::get_goto_functions()
960
957
return goto_functions;
961
958
}
962
959
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
-
1025
960
bool code_contractst::check_for_looped_mallocs (const goto_programt &program)
1026
961
{
1027
962
// Collect all GOTOs and mallocs
@@ -1101,9 +1036,9 @@ bool code_contractst::check_frame_conditions_function(const irep_idt &function)
1101
1036
auto &function_body = function_obj->second .body ;
1102
1037
1103
1038
// Get assigns clause for function
1104
- const symbolt &function_sybmol = ns.lookup (function);
1039
+ const symbolt &function_symbol = ns.lookup (function);
1105
1040
const auto &function_with_contract =
1106
- to_code_with_contract_type (function_sybmol .type );
1041
+ to_code_with_contract_type (function_symbol .type );
1107
1042
1108
1043
instrument_spec_assignst instrument_spec_assigns (
1109
1044
function, goto_functions, symbol_table, log .get_message_handler ());
@@ -1158,7 +1093,7 @@ bool code_contractst::check_frame_conditions_function(const irep_idt &function)
1158
1093
1159
1094
// Track formal parameters
1160
1095
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 ())
1162
1097
{
1163
1098
goto_programt payload;
1164
1099
instrument_spec_assigns.track_stack_allocated (
@@ -1170,184 +1105,16 @@ bool code_contractst::check_frame_conditions_function(const irep_idt &function)
1170
1105
goto_functions.update ();
1171
1106
1172
1107
// Insert write set inclusion checks.
1173
- check_frame_conditions (
1174
- function,
1108
+ instrument_spec_assigns.instrument_instructions (
1175
1109
function_body,
1176
1110
instruction_it,
1177
1111
function_body.instructions .end (),
1178
- instrument_spec_assigns,
1179
- // skip checks on function parameter assignments
1180
- skipt::Skip,
1112
+ skip_function_paramst::YES,
1181
1113
cfg_info_opt);
1182
1114
1183
1115
return false ;
1184
1116
}
1185
1117
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
-
1351
1118
bool code_contractst::enforce_contract (const irep_idt &function)
1352
1119
{
1353
1120
// Add statements to the source function
0 commit comments