33
33
#include < ansi-c/cprover_library.h>
34
34
// #include <goto-instrument/loop_utils.h>
35
35
36
+ #include " instrument_spec_assigns.h"
36
37
#include " utils.h"
37
38
38
39
#include < iostream>
@@ -1209,7 +1210,15 @@ void dfcct::to_dfcc_checked_function(const irep_idt &function_id)
1209
1210
log .debug () << " dfcc: to_dfcc_checked_function(" << function_id << " )"
1210
1211
<< messaget::eom;
1211
1212
1212
- // TODO fix problem with local_bitvector_analysis on library functions
1213
+
1214
+ // Create the cfg_info instance on a copy of the program before
1215
+ // instrumentation
1216
+ auto &goto_function = goto_model.goto_functions .function_map .at (function_id);
1217
+ goto_functiont goto_function_copy;
1218
+ goto_function_copy.copy_from (goto_function);
1219
+ const auto ns = namespacet (goto_model.symbol_table );
1220
+ cfg_infot cfg_info (ns, goto_function_copy);
1221
+
1213
1222
const auto &function_symbol = get_function_symbol (function_id);
1214
1223
1215
1224
// generate parameter symbols
@@ -1223,12 +1232,13 @@ void dfcct::to_dfcc_checked_function(const irep_idt &function_id)
1223
1232
1224
1233
add_dfcc_params (dfcc_params, function_id);
1225
1234
1226
- instrument_function_body (function_id, dfcc_params);
1235
+ instrument_function_body (function_id, dfcc_params, cfg_info );
1227
1236
}
1228
1237
1229
1238
void dfcct::instrument_function_body (
1230
1239
const irep_idt &function_id,
1231
- const dfcc_parameter_symbolst &dfcc_params)
1240
+ const dfcc_parameter_symbolst &dfcc_params,
1241
+ cfg_infot cfg_info)
1232
1242
{
1233
1243
auto &goto_function = goto_model.goto_functions .function_map .at (function_id);
1234
1244
@@ -1243,9 +1253,6 @@ void dfcct::instrument_function_body(
1243
1253
auto &function_symbol = get_function_symbol (function_id);
1244
1254
auto &body = goto_function.body ;
1245
1255
1246
- // we might need to duplicate the goto_function to keep the analysis working
1247
- // as we modify the function body
1248
-
1249
1256
// add local declaration for __stack_allocated
1250
1257
goto_programt preamble;
1251
1258
preamble.add (goto_programt::make_decl (
@@ -1266,16 +1273,17 @@ void dfcct::instrument_function_body(
1266
1273
1267
1274
body.destructive_insert (body.instructions .begin (), preamble);
1268
1275
1269
- // TODO add the DEAD instruction for stack_allocated at the end
1276
+ // Insert ` DEAD stack_allocated` before END_FUNCTION
1270
1277
goto_programt::targett end_function = body.get_end_function ();
1271
1278
goto_programt::instructiont dead_inst = goto_programt::make_dead (
1272
1279
dfcc_params.stack_allocated .symbol_expr (), function_symbol.location );
1273
1280
body.insert_before_swap (end_function, dead_inst);
1274
1281
1275
1282
const auto ns = namespacet (goto_model.symbol_table );
1276
- optionalt<cfg_infot> cfg_info_opt =
1277
- optionalt<cfg_infot>{cfg_infot{ns, goto_function}};
1278
1283
1284
+ optionalt<cfg_infot> cfg_info_opt{cfg_info};
1285
+
1286
+ // instrument the whole body
1279
1287
instrument_instructions (
1280
1288
function_id,
1281
1289
dfcc_params,
@@ -1319,6 +1327,7 @@ void dfcct::instrument_instructions(
1319
1327
while (target != last_instruction) // excluding the last
1320
1328
{
1321
1329
// Skip instructions marked as disabled for assigns clause checking
1330
+ // or rejected by the predicate
1322
1331
if (
1323
1332
// TODO
1324
1333
// has_disable_assigns_check_pragma(target) ||
@@ -1331,53 +1340,234 @@ void dfcct::instrument_instructions(
1331
1340
// Do not instrument this instruction again in the future,
1332
1341
// since we are going to instrument it now below.
1333
1342
// TODO
1334
- // add_pragma_disable_assigns_check(*target);
1343
+ add_pragma_disable_assigns_check (*target);
1335
1344
1336
- if (
1337
- target->is_decl () &&
1338
- must_track_decl (target, cfg_info_opt))
1345
+ if (target->is_decl () && must_track_decl_or_dead (target, cfg_info_opt))
1346
+ {
1347
+ instrument_decl (
1348
+ function_id, dfcc_params, target, goto_program, cfg_info_opt);
1349
+ }
1350
+ if (target->is_dead () && must_track_decl_or_dead (target, cfg_info_opt))
1339
1351
{
1340
- // // grab the declared symbol
1341
- // const auto &decl_symbol = target->decl_symbol();
1342
- // // move past the call and then insert the CAR
1343
- // target++;
1344
- // // since CAR was inserted *after* the DECL instruction,
1345
- // // move the instruction pointer backward,
1346
- // // because the enclosing while loop step takes
1347
- // // care of the increment
1348
- // target--;
1352
+ instrument_dead (
1353
+ function_id, dfcc_params, target, goto_program, cfg_info_opt);
1349
1354
}
1350
1355
else if (
1351
1356
target->is_assign () &&
1352
1357
must_check_assign (target, skip_function_params, cfg_info_opt))
1353
1358
{
1354
- instrument_assign (target, goto_program, cfg_info_opt);
1359
+ instrument_assign (
1360
+ function_id, dfcc_params, target, goto_program, cfg_info_opt);
1355
1361
}
1356
1362
else if (target->is_function_call ())
1357
1363
{
1358
- instrument_fuction_call (target, goto_program, cfg_info_opt);
1364
+ instrument_function_call (
1365
+ function_id, dfcc_params, target, goto_program, cfg_info_opt);
1359
1366
}
1360
- else if (
1361
- target->is_dead () &&
1362
- must_track_dead (target, cfg_info_opt))
1367
+ else if (target->is_other ())
1363
1368
{
1364
- // const auto &symbol = target->dead_symbol();
1365
- // // TODO
1369
+ instrument_other (
1370
+ function_id, dfcc_params, target, goto_program, cfg_info_opt);
1366
1371
}
1367
- else if (
1368
- target->is_other () &&
1369
- target->get_other ().get_statement () == ID_havoc_object)
1372
+ // else do nothing
1373
+ target++;
1374
+ }
1375
+ }
1376
+
1377
+ bool dfcct::must_track_decl_or_dead (
1378
+ const goto_programt::targett &target,
1379
+ const optionalt<cfg_infot> &cfg_info_opt) const
1380
+ {
1381
+ INVARIANT (
1382
+ target->is_decl () || target->is_dead (),
1383
+ " the target must be a DECL or DEAD instruction" );
1384
+
1385
+ const auto &ident = target->is_decl ()
1386
+ ? target->decl_symbol ().get_identifier ()
1387
+ : target->dead_symbol ().get_identifier ();
1388
+ return !cfg_info_opt.has_value () ||
1389
+ (cfg_info_opt.has_value () &&
1390
+ cfg_info_opt.value ().is_not_local_or_dirty_local (ident));
1391
+ }
1392
+
1393
+ void dfcct::instrument_decl (
1394
+ const irep_idt &function_id,
1395
+ const dfcc_parameter_symbolst &dfcc_params,
1396
+ goto_programt::targett &target,
1397
+ goto_programt &goto_program,
1398
+ optionalt<cfg_infot> &cfg_info_opt)
1399
+ {
1400
+ // // grab the declared symbol
1401
+ // const auto &decl_symbol = target->decl_symbol();
1402
+ // // move past the call and then insert the CAR
1403
+ // target++;
1404
+ // // since CAR was inserted *after* the DECL instruction,
1405
+ // // move the instruction pointer backward,
1406
+ // // because the enclosing while loop step takes
1407
+ // // care of the increment
1408
+ // target--;
1409
+ }
1410
+
1411
+ void dfcct::instrument_dead (
1412
+ const irep_idt &function_id,
1413
+ const dfcc_parameter_symbolst &dfcc_params,
1414
+ goto_programt::targett &target,
1415
+ goto_programt &goto_program,
1416
+ optionalt<cfg_infot> &cfg_info_opt)
1417
+ {
1418
+ }
1419
+
1420
+ // / Returns true iff an `ASSIGN lhs := rhs` instruction must be instrumented.
1421
+ bool dfcct::must_check_assign (
1422
+ const goto_programt::const_targett &target,
1423
+ dfcc_skip_function_paramst skip_function_params,
1424
+ const optionalt<cfg_infot> &cfg_info_opt)
1425
+ {
1426
+ log .debug ().source_location = target->source_location ();
1427
+
1428
+ if (can_cast_expr<symbol_exprt>(target->assign_lhs ()))
1429
+ {
1430
+ const auto &symbol_expr = to_symbol_expr (target->assign_lhs ());
1431
+ if (
1432
+ skip_function_params == dfcc_skip_function_paramst::NO &&
1433
+ goto_model.symbol_table .lookup_ref (symbol_expr.get_identifier ())
1434
+ .is_parameter )
1370
1435
{
1371
- // // TODO array copy and the rest
1372
- // auto havoc_argument = target->get_other().operands().front() ;
1373
- // auto havoc_object = pointer_object(havoc_argument) ;
1436
+ log . debug () << " dfcc: checking assignment to function parameter "
1437
+ << format (symbol_expr) << messaget::eom ;
1438
+ return true ;
1374
1439
}
1375
1440
1376
- // Move to the next instruction
1377
- target++;
1441
+ if (cfg_info_opt.has_value ())
1442
+ {
1443
+ if (cfg_info_opt.value ().is_local (symbol_expr.get_identifier ()))
1444
+ {
1445
+ log .debug () << " dfcc: skipping checking on assignment to local symbol "
1446
+ << format (symbol_expr) << messaget::eom;
1447
+ return false ;
1448
+ }
1449
+ else
1450
+ {
1451
+ log .debug () << " dfcc: checking assignment to non-local symbol "
1452
+ << format (symbol_expr) << messaget::eom;
1453
+ return true ;
1454
+ }
1455
+ }
1456
+ log .debug () << " dfcc: checking assignment to symbol " << format (symbol_expr)
1457
+ << messaget::eom;
1458
+ return true ;
1378
1459
}
1460
+ else
1461
+ {
1462
+ // This is not a mere symbol.
1463
+ // Since non-dirty locals are not tracked explicitly in the write set,
1464
+ // we need to skip the check if we can verify that the expression describes
1465
+ // an access to a non-dirty local symbol or an input parameter,
1466
+ // otherwise the check will fail.
1467
+ // In addition, the expression shall not contain address_of or dereference
1468
+ // operators, regardless of the base symbol/object on which they apply.
1469
+ // If the expression contains an address_of operation, the assignment gets
1470
+ // checked. If the base object is a local or a parameter, it will also be
1471
+ // flagged as dirty and will be tracked explicitly, and the check will pass.
1472
+ // If the expression contains a dereference operation, the assignment gets
1473
+ // checked. If the dereferenced address was computed from a local object,
1474
+ // from a function parameter or returned by a local malloc,
1475
+ // then the object will be tracked explicitly and the check will pass.
1476
+ // In all other cases (address of a non-local object, or dereference of
1477
+ // a non-locally computed address) the location must be given explicitly
1478
+ // in the assigns clause to be tracked and we must check the assignment.
1479
+ if (
1480
+ cfg_info_opt.has_value () &&
1481
+ cfg_info_opt.value ().is_local_composite_access (target->assign_lhs ()))
1482
+ {
1483
+ log .debug () << " dfcc: skipping check on assignment to local composite "
1484
+ " member expression "
1485
+ << format (target->assign_lhs ()) << messaget::eom;
1486
+ return false ;
1487
+ }
1488
+ log .debug () << " dfcc: checking assignment to expression "
1489
+ << format (target->assign_lhs ()) << messaget::eom;
1490
+ return true ;
1491
+ }
1492
+ }
1493
+
1494
+ void dfcct::instrument_assign (
1495
+ const irep_idt &function_id,
1496
+ const dfcc_parameter_symbolst &dfcc_params,
1497
+ goto_programt::targett &target,
1498
+ goto_programt &goto_program,
1499
+ optionalt<cfg_infot> &cfg_info_opt)
1500
+ {
1379
1501
}
1380
1502
1503
+ void dfcct::instrument_function_call (
1504
+ const irep_idt &function_id,
1505
+ const dfcc_parameter_symbolst &dfcc_params,
1506
+ goto_programt::targett &target,
1507
+ goto_programt &goto_program,
1508
+ optionalt<cfg_infot> &cfg_info_opt)
1509
+ {
1510
+ INVARIANT (
1511
+ target->is_function_call (),
1512
+ " the target must be a function call instruction" );
1513
+
1514
+ // do we have a function symbol or a complex expression ?
1515
+ const auto &callee_expr = target->call_function ();
1516
+ if (callee_expr.id () == ID_symbol)
1517
+ {
1518
+ // we have a function symbol
1519
+ const auto &callee_id =
1520
+ id2string (to_symbol_expr (callee_expr).get_identifier ());
1521
+
1522
+ if (callee_id == CPROVER_PREFIX " allocate" )
1523
+ {
1524
+ // heap allocation
1525
+ }
1526
+ else if (callee_id == CPROVER_PREFIX " deallocate" )
1527
+ {
1528
+ // heap deallocation
1529
+ }
1530
+ else if (callee_id == " __builtin_alloca" )
1531
+ {
1532
+ // dynamic stack allocation
1533
+ }
1534
+ else
1535
+ {
1536
+ // user defined or library function
1537
+ // propagate dfcc parameters
1538
+ }
1539
+ }
1540
+ else
1541
+ {
1542
+ // we have a function pointer expression
1543
+ // propagate the dfcc params
1544
+ }
1545
+ }
1546
+
1547
+ void dfcct::instrument_other (
1548
+ const irep_idt &function_id,
1549
+ const dfcc_parameter_symbolst &dfcc_params,
1550
+ goto_programt::targett &target,
1551
+ goto_programt &goto_program,
1552
+ optionalt<cfg_infot> &cfg_info_opt)
1553
+ {
1554
+ auto &statement = target->get_other ().get_statement ();
1555
+ if (statement == ID_array_set)
1556
+ {
1557
+ }
1558
+ else if (statement == ID_array_copy)
1559
+ {
1560
+ }
1561
+ else if (statement == ID_array_replace)
1562
+ {
1563
+ }
1564
+ else if (statement == ID_havoc_object)
1565
+ {
1566
+ }
1567
+ else
1568
+ {
1569
+ }
1570
+ }
1381
1571
1382
1572
const symbolt &dfcct::clone_and_rename_function (
1383
1573
const irep_idt &function_id,
0 commit comments