Skip to content

Commit 2bd210a

Browse files
author
Remi Delmas
committed
CONTRACTS: loop assigns clause inference function
Utility function for loop contracts instrumentation.
1 parent b34e991 commit 2bd210a

File tree

3 files changed

+146
-0
lines changed

3 files changed

+146
-0
lines changed

src/goto-instrument/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ SRC = accelerate/accelerate.cpp \
1818
call_sequences.cpp \
1919
contracts/contracts.cpp \
2020
contracts/dynamic-frames/dfcc_utils.cpp \
21+
contracts/dynamic-frames/dfcc_infer_loop_assigns.cpp \
2122
contracts/dynamic-frames/dfcc_library.cpp \
2223
contracts/dynamic-frames/dfcc_is_fresh.cpp \
2324
contracts/dynamic-frames/dfcc_pointer_in_range.cpp \
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
/*******************************************************************\
2+
3+
Module: Dynamic frame condition checking
4+
5+
Author: Remi Delmas, [email protected]
6+
7+
\*******************************************************************/
8+
#include "dfcc_infer_loop_assigns.h"
9+
10+
#include <util/expr.h>
11+
#include <util/find_symbols.h>
12+
#include <util/message.h>
13+
#include <util/pointer_expr.h>
14+
#include <util/std_code.h>
15+
16+
#include <goto-instrument/havoc_utils.h>
17+
18+
/// Widens expressions in the given \p assigns set as follows:
19+
/// If an expression is an array index expression or an object dereference
20+
/// expression with a non-constant offset, e.g. a[i] or *(b+i) with a
21+
/// non-constant `i`, then replace it by the entire underlying object.
22+
/// Otherwise, e.g. for a[i] or *(b+i) when `i` is a known constant,
23+
/// keep the expression in the result.
24+
/// By `constant` for the index expression, we do not mean a literal constant
25+
/// expression. Rather, we mean a symbol or an expression the value of which is
26+
/// known not to change over loop iterations, i.e. an expression that is not
27+
/// itself part of \p assigns.
28+
static void dfcc_widen_non_const(const namespacet &ns, assignst &assigns)
29+
{
30+
assignst result;
31+
const symbolt &object_whole_sym = ns.lookup(CPROVER_PREFIX "object_whole");
32+
code_typet object_whole_code_type = to_code_type(object_whole_sym.type);
33+
havoc_utils_is_constantt is_constant(assigns, ns);
34+
35+
for(const auto &e : assigns)
36+
{
37+
if(e.id() == ID_index || e.id() == ID_dereference)
38+
{
39+
address_of_exprt address_of_expr(e);
40+
41+
// index or offset is non-constant.
42+
if(!is_constant(address_of_expr))
43+
{
44+
exprt::operandst args;
45+
args.emplace_back(address_of_expr);
46+
result.emplace(side_effect_expr_function_callt(
47+
object_whole_sym.symbol_expr(),
48+
args,
49+
object_whole_code_type.return_type(),
50+
address_of_expr.source_location()));
51+
}
52+
else
53+
result.emplace(e);
54+
}
55+
else
56+
result.emplace(e);
57+
}
58+
assigns.swap(result);
59+
}
60+
61+
std::set<exprt> dfcc_infer_loop_assigns(
62+
const local_may_aliast &local_may_alias,
63+
const loopt &loop_instructions,
64+
const source_locationt &loop_head_location,
65+
messaget &log,
66+
namespacet &ns)
67+
{
68+
try
69+
{
70+
// infer
71+
assignst assigns;
72+
get_assigns(local_may_alias, loop_instructions, assigns);
73+
74+
// compute locals
75+
std::set<irep_idt> loop_locals;
76+
for(const auto &target : loop_instructions)
77+
{
78+
if(target->is_decl())
79+
{
80+
loop_locals.insert(target->decl_symbol().get_identifier());
81+
}
82+
}
83+
84+
// remove all targets that depend on loop-local identifiers
85+
auto expr_it = assigns.begin();
86+
while(expr_it != assigns.end())
87+
{
88+
const std::unordered_set<irep_idt> symbols =
89+
find_symbol_identifiers(*expr_it);
90+
91+
if(std::find_if(symbols.begin(), symbols.end(), [&](const irep_idt &id) {
92+
return loop_locals.find(id) != loop_locals.end();
93+
}) != symbols.end())
94+
{
95+
expr_it = assigns.erase(expr_it);
96+
}
97+
else
98+
{
99+
expr_it++;
100+
}
101+
}
102+
103+
// widen all targets that depend on non-constant expressions
104+
dfcc_widen_non_const(ns, assigns);
105+
return assigns;
106+
}
107+
catch(const analysis_exceptiont &exc)
108+
{
109+
log.error() << "Failed to infer memory locations assigned by the loop at "
110+
<< loop_head_location
111+
<< ".\nPlease specify an assigns clause.\nReason:"
112+
<< messaget::eom;
113+
throw exc;
114+
}
115+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*******************************************************************\
2+
3+
Module: Dynamic frame condition checking
4+
5+
Author: Remi Delmas, [email protected]
6+
7+
\*******************************************************************/
8+
9+
/// \file
10+
/// Infer a set of assigns clause targets for a natural loop.
11+
12+
#ifndef CPROVER_GOTO_INSTRUMENT_CONTRACTS_DYNAMIC_FRAMES_DFCC_INFER_LOOP_ASSIGNS_H
13+
#define CPROVER_GOTO_INSTRUMENT_CONTRACTS_DYNAMIC_FRAMES_DFCC_INFER_LOOP_ASSIGNS_H
14+
15+
#include <analyses/local_may_alias.h>
16+
#include <goto-instrument/loop_utils.h>
17+
class source_locationt;
18+
class messaget;
19+
class namespacet;
20+
21+
// \brief Infer assigns clause targets for a loop from its instructions and a
22+
// may alias analysis at the function level.
23+
std::set<exprt> dfcc_infer_loop_assigns(
24+
const local_may_aliast &local_may_alias,
25+
const loopt &loop_instructions,
26+
const source_locationt &loop_head_location,
27+
messaget &log,
28+
namespacet &ns);
29+
30+
#endif

0 commit comments

Comments
 (0)