Skip to content

Commit fc1cd2a

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

File tree

4 files changed

+155
-0
lines changed

4 files changed

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

src/goto-instrument/contracts/dynamic-frames/module_dependencies.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
analyses
12
ansi-c
23
goto-instrument/contracts
34
goto-instrument/contracts/dynamic-frames

0 commit comments

Comments
 (0)