Skip to content

Commit 6b828d5

Browse files
author
Remi Delmas
committed
CONTRACTS: functions to compute root objects
Alternative implementation of `root_object` supporting ternary operators in assignment or call LHS expressions, and object slice expressions in assigns clause targets.
1 parent 53b50bc commit 6b828d5

File tree

3 files changed

+168
-0
lines changed

3 files changed

+168
-0
lines changed

src/goto-instrument/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ SRC = accelerate/accelerate.cpp \
2323
contracts/dynamic-frames/dfcc_loop_contract_mode.cpp \
2424
contracts/dynamic-frames/dfcc_loop_tags.cpp \
2525
contracts/dynamic-frames/dfcc_check_loop_normal_form.cpp \
26+
contracts/dynamic-frames/dfcc_root_object.cpp \
2627
contracts/dynamic-frames/dfcc_library.cpp \
2728
contracts/dynamic-frames/dfcc_is_cprover_symbol.cpp \
2829
contracts/dynamic-frames/dfcc_is_fresh.cpp \
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
/*******************************************************************\
2+
3+
Module: Dynamic frame condition checking
4+
5+
Author: Remi Delmas, [email protected]
6+
7+
Date: March 2023
8+
9+
\*******************************************************************/
10+
11+
#include "dfcc_root_object.h"
12+
13+
#include <util/byte_operators.h>
14+
#include <util/cprover_prefix.h>
15+
#include <util/expr.h>
16+
#include <util/expr_util.h>
17+
#include <util/pointer_expr.h>
18+
#include <util/std_code.h>
19+
20+
#include <goto-programs/pointer_arithmetic.h>
21+
22+
/// Recursively computes a set of root object expressions for \p expr.
23+
static void
24+
root_objects_rec(const exprt &expr, std::unordered_set<exprt, irep_hash> &dest)
25+
{
26+
if(expr.id() == ID_symbol)
27+
{
28+
dest.insert(expr);
29+
}
30+
else if(expr.id() == ID_index)
31+
{
32+
root_objects_rec(to_index_expr(expr).array(), dest);
33+
}
34+
else if(expr.id() == ID_member)
35+
{
36+
const typet &type = to_member_expr(expr).struct_op().type();
37+
DATA_INVARIANT(
38+
type.id() == ID_struct || type.id() == ID_struct_tag ||
39+
type.id() == ID_union || type.id() == ID_union_tag,
40+
"unexpected assignment to member of '" + type.id_string() + "'");
41+
root_objects_rec(to_member_expr(expr).compound(), dest);
42+
}
43+
else if(expr.id() == ID_if)
44+
{
45+
root_objects_rec(to_if_expr(expr).true_case(), dest);
46+
root_objects_rec(to_if_expr(expr).false_case(), dest);
47+
}
48+
else if(expr.id() == ID_typecast)
49+
{
50+
root_objects_rec(to_typecast_expr(expr).op(), dest);
51+
}
52+
else if(
53+
expr.id() == ID_byte_extract_little_endian ||
54+
expr.id() == ID_byte_extract_big_endian)
55+
{
56+
root_objects_rec(to_byte_extract_expr(expr).op(), dest);
57+
}
58+
else if(expr.id() == ID_complex_real)
59+
{
60+
root_objects_rec(to_complex_real_expr(expr).op(), dest);
61+
}
62+
else if(expr.id() == ID_complex_imag)
63+
{
64+
root_objects_rec(to_complex_imag_expr(expr).op(), dest);
65+
}
66+
else if(const auto &deref = expr_try_dynamic_cast<dereference_exprt>(expr))
67+
{
68+
// normalise the dereferenced pointer into `pointer + offset`, extract
69+
// pointer expression and try some simplifications
70+
const exprt &pointer = pointer_arithmetict(deref->pointer()).pointer;
71+
const source_locationt source_location = expr.source_location();
72+
if(const auto &if_expr = expr_try_dynamic_cast<if_exprt>(pointer))
73+
{
74+
// split on disjunctions
75+
// *(c ? true_case : false_case) => rec(*true_case); rec(*false_case)
76+
dereference_exprt if_true(if_expr->true_case());
77+
if_true.add_source_location() = source_location;
78+
root_objects_rec(if_true, dest);
79+
dereference_exprt if_false(if_expr->false_case());
80+
if_false.add_source_location() = source_location;
81+
root_objects_rec(if_false, dest);
82+
}
83+
else if(
84+
const auto &address_of_expr =
85+
expr_try_dynamic_cast<address_of_exprt>(pointer))
86+
{
87+
// *(&object + offset) => rec(object)
88+
root_objects_rec(skip_typecast(address_of_expr->object()), dest);
89+
}
90+
else
91+
{
92+
// simplify *(pointer + offset) to *pointer and stop here
93+
dereference_exprt deref(pointer);
94+
deref.add_source_location() = source_location;
95+
dest.insert(deref);
96+
}
97+
}
98+
else
99+
{
100+
// Stop here for anything else.
101+
dest.insert(expr);
102+
}
103+
}
104+
105+
/// Translates object slice expressions found in assigns clause targets to
106+
/// dereference expressions so that root objects can be computed.
107+
static exprt slice_op_to_deref(const exprt &expr)
108+
{
109+
if(
110+
const auto &function_call_expr =
111+
expr_try_dynamic_cast<side_effect_expr_function_callt>(expr))
112+
{
113+
auto function_expr = function_call_expr->function();
114+
INVARIANT(
115+
function_expr.id() == ID_symbol,
116+
"no function pointer calls in loop assigns clause targets");
117+
auto function_id = to_symbol_expr(function_expr).get_identifier();
118+
INVARIANT(
119+
function_id == CPROVER_PREFIX "assignable" ||
120+
function_id == CPROVER_PREFIX "object_whole" ||
121+
function_id == CPROVER_PREFIX "object_from" ||
122+
function_id == CPROVER_PREFIX "object_upto",
123+
"can only handle built-in function calls in assigns clause targets");
124+
return dereference_exprt(
125+
skip_typecast(function_call_expr->arguments().at(0)));
126+
}
127+
else
128+
{
129+
return expr;
130+
}
131+
}
132+
133+
std::unordered_set<exprt, irep_hash> dfcc_root_objects(const exprt &expr)
134+
{
135+
std::unordered_set<exprt, irep_hash> result;
136+
root_objects_rec(slice_op_to_deref(expr), result);
137+
return result;
138+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*******************************************************************\
2+
3+
Module: Dynamic frame condition checking
4+
5+
Author: Remi Delmas, [email protected]
6+
7+
Date: March 2023
8+
9+
\*******************************************************************/
10+
11+
/// \file
12+
/// Utility functions that compute root object expressions for assigns clause
13+
/// targets and LHS expressions.
14+
15+
#ifndef CPROVER_GOTO_INSTRUMENT_CONTRACTS_DYNAMIC_FRAMES_DFCC_ROOT_OBJECT_H
16+
#define CPROVER_GOTO_INSTRUMENT_CONTRACTS_DYNAMIC_FRAMES_DFCC_ROOT_OBJECT_H
17+
18+
#include <util/irep.h>
19+
20+
#include <unordered_set>
21+
22+
class exprt;
23+
24+
/// Computes a set of root object expressions from an lvalue or assigns clause
25+
/// target expression. A root object expression is a simpler expression that
26+
/// denotes the object that contains the memory location refered to by the
27+
/// initial expression.
28+
std::unordered_set<exprt, irep_hash> dfcc_root_objects(const exprt &expr);
29+
#endif

0 commit comments

Comments
 (0)