@@ -33,6 +33,7 @@ Author: Remi Delmas, delmarsd@amazon.com
3333#include < ansi-c/cprover_library.h>
3434// #include <goto-instrument/loop_utils.h>
3535
36+ #include " instrument_spec_assigns.h"
3637#include " utils.h"
3738
3839#include < iostream>
@@ -1209,7 +1210,15 @@ void dfcct::to_dfcc_checked_function(const irep_idt &function_id)
12091210 log.debug () << " dfcc: to_dfcc_checked_function(" << function_id << " )"
12101211 << messaget::eom;
12111212
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+
12131222 const auto &function_symbol = get_function_symbol (function_id);
12141223
12151224 // generate parameter symbols
@@ -1223,12 +1232,13 @@ void dfcct::to_dfcc_checked_function(const irep_idt &function_id)
12231232
12241233 add_dfcc_params (dfcc_params, function_id);
12251234
1226- instrument_function_body (function_id, dfcc_params);
1235+ instrument_function_body (function_id, dfcc_params, cfg_info );
12271236}
12281237
12291238void dfcct::instrument_function_body (
12301239 const irep_idt &function_id,
1231- const dfcc_parameter_symbolst &dfcc_params)
1240+ const dfcc_parameter_symbolst &dfcc_params,
1241+ cfg_infot cfg_info)
12321242{
12331243 auto &goto_function = goto_model.goto_functions .function_map .at (function_id);
12341244
@@ -1243,9 +1253,6 @@ void dfcct::instrument_function_body(
12431253 auto &function_symbol = get_function_symbol (function_id);
12441254 auto &body = goto_function.body ;
12451255
1246- // we might need to duplicate the goto_function to keep the analysis working
1247- // as we modify the function body
1248-
12491256 // add local declaration for __stack_allocated
12501257 goto_programt preamble;
12511258 preamble.add (goto_programt::make_decl (
@@ -1266,16 +1273,17 @@ void dfcct::instrument_function_body(
12661273
12671274 body.destructive_insert (body.instructions .begin (), preamble);
12681275
1269- // TODO add the DEAD instruction for stack_allocated at the end
1276+ // Insert ` DEAD stack_allocated` before END_FUNCTION
12701277 goto_programt::targett end_function = body.get_end_function ();
12711278 goto_programt::instructiont dead_inst = goto_programt::make_dead (
12721279 dfcc_params.stack_allocated .symbol_expr (), function_symbol.location );
12731280 body.insert_before_swap (end_function, dead_inst);
12741281
12751282 const auto ns = namespacet (goto_model.symbol_table );
1276- optionalt<cfg_infot> cfg_info_opt =
1277- optionalt<cfg_infot>{cfg_infot{ns, goto_function}};
12781283
1284+ optionalt<cfg_infot> cfg_info_opt{cfg_info};
1285+
1286+ // instrument the whole body
12791287 instrument_instructions (
12801288 function_id,
12811289 dfcc_params,
@@ -1319,6 +1327,7 @@ void dfcct::instrument_instructions(
13191327 while (target != last_instruction) // excluding the last
13201328 {
13211329 // Skip instructions marked as disabled for assigns clause checking
1330+ // or rejected by the predicate
13221331 if (
13231332 // TODO
13241333 // has_disable_assigns_check_pragma(target) ||
@@ -1331,53 +1340,234 @@ void dfcct::instrument_instructions(
13311340 // Do not instrument this instruction again in the future,
13321341 // since we are going to instrument it now below.
13331342 // TODO
1334- // add_pragma_disable_assigns_check(*target);
1343+ add_pragma_disable_assigns_check (*target);
13351344
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))
13391351 {
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);
13491354 }
13501355 else if (
13511356 target->is_assign () &&
13521357 must_check_assign (target, skip_function_params, cfg_info_opt))
13531358 {
1354- instrument_assign (target, goto_program, cfg_info_opt);
1359+ instrument_assign (
1360+ function_id, dfcc_params, target, goto_program, cfg_info_opt);
13551361 }
13561362 else if (target->is_function_call ())
13571363 {
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);
13591366 }
1360- else if (
1361- target->is_dead () &&
1362- must_track_dead (target, cfg_info_opt))
1367+ else if (target->is_other ())
13631368 {
1364- // const auto &symbol = target->dead_symbol();
1365- // // TODO
1369+ instrument_other (
1370+ function_id, dfcc_params, target, goto_program, cfg_info_opt);
13661371 }
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 )
13701435 {
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 ;
13741439 }
13751440
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 ;
13781459 }
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+ {
13791501}
13801502
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+ }
13811571
13821572const symbolt &dfcct::clone_and_rename_function (
13831573 const irep_idt &function_id,
0 commit comments