Skip to content

Commit 61748d2

Browse files
author
Remi Delmas
committed
full instruction dispatch structure
1 parent defc43a commit 61748d2

File tree

3 files changed

+255
-50
lines changed

3 files changed

+255
-50
lines changed

src/goto-instrument/contracts/dfcc.cpp

+227-37
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ Author: Remi Delmas, [email protected]
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

12291238
void 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

13821572
const symbolt &dfcct::clone_and_rename_function(
13831573
const irep_idt &function_id,

0 commit comments

Comments
 (0)