1
1
/* ******************************************************************\
2
2
3
- Module: Specify write set in function contracts.
3
+ Module: Specify write set in code contracts.
4
4
5
5
Author: Felipe R. Monteiro
6
6
@@ -19,129 +19,112 @@ Date: July 2021
19
19
#include < util/c_types.h>
20
20
#include < util/pointer_predicates.h>
21
21
22
- assigns_clause_targett::assigns_clause_targett (
23
- const exprt &object,
24
- code_contractst &contract,
25
- messaget &log_parameter,
26
- const irep_idt &function_id)
27
- : contract(contract),
28
- init_block(),
29
- log(log_parameter),
30
- target(pointer_for(object)),
31
- target_id(object.id())
22
+ assigns_clauset::targett::targett (
23
+ const assigns_clauset &parent,
24
+ const exprt &expr)
25
+ : expr(address_of_exprt(expr)), id(expr.id()), parent(parent)
32
26
{
33
- INVARIANT (
34
- target.type ().id () == ID_pointer,
35
- " Assigns clause targets should be stored as pointer expressions." );
36
27
}
37
28
38
- assigns_clause_targett::~assigns_clause_targett ( )
29
+ exprt assigns_clauset::targett::normalize ( const exprt &expr )
39
30
{
31
+ if (expr.id () != ID_address_of)
32
+ return expr;
33
+
34
+ const auto &object = to_address_of_expr (expr).object ();
35
+ if (object.id () != ID_index)
36
+ return object;
37
+
38
+ return to_index_expr (object).array ();
40
39
}
41
40
42
- exprt assigns_clause_targett::alias_expression (const exprt &lhs)
41
+ exprt assigns_clauset::targett::generate_alias_check (const exprt &lhs) const
43
42
{
44
43
exprt::operandst condition;
45
- exprt lhs_ptr = (lhs. id () == ID_address_of) ? to_address_of_expr (lhs). object ()
46
- : pointer_for (lhs);
44
+ const auto lhs_ptr =
45
+ (lhs. id () == ID_address_of) ? lhs : address_of_exprt (lhs);
47
46
48
47
// __CPROVER_w_ok(target, sizeof(target))
49
48
condition.push_back (w_ok_exprt (
50
- target,
51
- size_of_expr (dereference_exprt (target).type (), contract.ns ).value ()));
49
+ expr, size_of_expr (dereference_exprt (expr).type (), parent.ns ).value ()));
52
50
53
51
// __CPROVER_same_object(lhs, target)
54
- condition.push_back (same_object (lhs_ptr, target ));
52
+ condition.push_back (same_object (lhs_ptr, expr ));
55
53
56
54
// If assigns target was a dereference, comparing objects is enough
57
- if (target_id == ID_dereference)
55
+ if (id == ID_dereference)
58
56
{
59
57
return conjunction (condition);
60
58
}
61
59
62
- const exprt lhs_offset = pointer_offset (lhs_ptr);
63
- const exprt target_offset = pointer_offset (target );
60
+ const auto lhs_offset = pointer_offset (lhs_ptr);
61
+ const auto own_offset = pointer_offset (expr );
64
62
65
63
// __CPROVER_offset(lhs) >= __CPROVER_offset(target)
66
- condition.push_back (binary_relation_exprt (lhs_offset, ID_ge, target_offset ));
64
+ condition.push_back (binary_relation_exprt (lhs_offset, ID_ge, own_offset ));
67
65
68
- const exprt region_lhs = plus_exprt (
66
+ const auto lhs_region = plus_exprt (
69
67
typecast_exprt::conditional_cast (
70
- size_of_expr (lhs.type (), contract .ns ).value (), lhs_offset.type ()),
68
+ size_of_expr (lhs.type (), parent .ns ).value (), lhs_offset.type ()),
71
69
lhs_offset);
72
70
73
- const exprt region_target = plus_exprt (
71
+ const exprt own_region = plus_exprt (
74
72
typecast_exprt::conditional_cast (
75
- size_of_expr (dereference_exprt (target ).type (), contract .ns ).value (),
76
- target_offset .type ()),
77
- target_offset );
73
+ size_of_expr (dereference_exprt (expr ).type (), parent .ns ).value (),
74
+ own_offset .type ()),
75
+ own_offset );
78
76
79
77
// (sizeof(lhs) + __CPROVER_offset(lhs)) <=
80
78
// (sizeof(target) + __CPROVER_offset(target))
81
- condition.push_back (binary_relation_exprt (region_lhs , ID_le, region_target ));
79
+ condition.push_back (binary_relation_exprt (lhs_region , ID_le, own_region ));
82
80
83
81
return conjunction (condition);
84
82
}
85
83
86
- exprt assigns_clause_targett::compatible_expression (
87
- const assigns_clause_targett &called_target)
88
- {
89
- return same_object (called_target.get_target (), target);
90
- }
91
-
92
- const exprt &assigns_clause_targett::get_target () const
84
+ exprt assigns_clauset::targett::generate_compatibility_check (
85
+ const assigns_clauset::targett &other_target) const
93
86
{
94
- return target ;
87
+ return same_object (other_target. expr , expr) ;
95
88
}
96
89
97
90
assigns_clauset::assigns_clauset (
98
- const exprt &assigns,
99
- code_contractst &contract,
100
- const irep_idt function_id,
101
- messaget log_parameter)
102
- : assigns(assigns),
103
- parent(contract),
104
- function_id(function_id),
105
- log(log_parameter)
91
+ const exprt &expr,
92
+ const messaget &log,
93
+ const namespacet &ns)
94
+ : expr(expr), log(log), ns(ns)
106
95
{
107
- for (exprt target : assigns .operands ())
96
+ for (const auto &target_expr : expr .operands ())
108
97
{
109
- add_target (target );
98
+ add_target (target_expr );
110
99
}
111
100
}
112
101
113
- assigns_clauset::~assigns_clauset ( )
102
+ void assigns_clauset::add_target ( const exprt &target_expr )
114
103
{
115
- for (assigns_clause_targett *target : targets)
104
+ auto insertion_succeeded =
105
+ targets.emplace (*this , targett::normalize (target_expr)).second ;
106
+
107
+ if (!insertion_succeeded)
116
108
{
117
- delete target;
109
+ log .warning () << " Ignored duplicate expression '"
110
+ << from_expr (ns, target_expr.id (), target_expr)
111
+ << " ' in assigns clause at "
112
+ << target_expr.source_location ().as_string () << messaget::eom;
118
113
}
119
114
}
120
115
121
- void assigns_clauset::add_target (exprt target)
122
- {
123
- assigns_clause_targett *new_target = new assigns_clause_targett (
124
- (target.id () == ID_address_of)
125
- ? to_index_expr (to_address_of_expr (target).object ()).array ()
126
- : target,
127
- parent,
128
- log ,
129
- function_id);
130
- targets.push_back (new_target);
131
- }
132
-
133
- goto_programt assigns_clauset::havoc_code ()
116
+ goto_programt assigns_clauset::generate_havoc_code () const
134
117
{
135
118
modifiest modifies;
136
- for (const auto &t : targets)
137
- modifies.insert (to_address_of_expr (t-> get_target () ).object ());
119
+ for (const auto &target : targets)
120
+ modifies.insert (to_address_of_expr (target. expr ).object ());
138
121
139
122
goto_programt havoc_statements;
140
- append_havoc_code (assigns .source_location (), modifies, havoc_statements);
123
+ append_havoc_code (expr .source_location (), modifies, havoc_statements);
141
124
return havoc_statements;
142
125
}
143
126
144
- exprt assigns_clauset::alias_expression (const exprt &lhs)
127
+ exprt assigns_clauset::generate_alias_check (const exprt &lhs) const
145
128
{
146
129
// If write set is empty, no assignment is allowed.
147
130
if (targets.empty ())
@@ -150,15 +133,15 @@ exprt assigns_clauset::alias_expression(const exprt &lhs)
150
133
}
151
134
152
135
exprt::operandst condition;
153
- for (assigns_clause_targett * target : targets)
136
+ for (const auto & target : targets)
154
137
{
155
- condition.push_back (target-> alias_expression (lhs));
138
+ condition.push_back (target. generate_alias_check (lhs));
156
139
}
157
140
return disjunction (condition);
158
141
}
159
142
160
- exprt assigns_clauset::compatible_expression (
161
- const assigns_clauset &called_assigns)
143
+ exprt assigns_clauset::generate_compatibility_check (
144
+ const assigns_clauset &called_assigns) const
162
145
{
163
146
if (called_assigns.targets .empty ())
164
147
{
@@ -167,11 +150,11 @@ exprt assigns_clauset::compatible_expression(
167
150
168
151
bool first_clause = true ;
169
152
exprt result = true_exprt ();
170
- for (assigns_clause_targett * called_target : called_assigns.targets )
153
+ for (const auto & called_target : called_assigns.targets )
171
154
{
172
155
bool first_iter = true ;
173
156
exprt current_target_compatible = false_exprt ();
174
- for (assigns_clause_targett * target : targets)
157
+ for (const auto & target : targets)
175
158
{
176
159
if (first_iter)
177
160
{
@@ -180,30 +163,30 @@ exprt assigns_clauset::compatible_expression(
180
163
181
164
// Validating the called target through __CPROVER_w_ok() is
182
165
// only useful when the called target is a dereference
183
- const auto &called_target_ptr = called_target-> get_target () ;
166
+ const auto &called_target_ptr = called_target. expr ;
184
167
if (
185
168
to_address_of_expr (called_target_ptr).object ().id () == ID_dereference)
186
169
{
187
170
// or_exprt is short-circuited, therefore
188
- // target->compatible_expression (*called_target) would not be
171
+ // target.generate_compatibility_check (*called_target) would not be
189
172
// checked on invalid called_targets.
190
173
current_target_compatible = or_exprt (
191
174
not_exprt (w_ok_exprt (
192
175
called_target_ptr, from_integer (0 , unsigned_int_type ()))),
193
- target-> compatible_expression (* called_target));
176
+ target. generate_compatibility_check ( called_target));
194
177
}
195
178
else
196
179
{
197
180
current_target_compatible =
198
- target-> compatible_expression (* called_target);
181
+ target. generate_compatibility_check ( called_target);
199
182
}
200
183
first_iter = false ;
201
184
}
202
185
else
203
186
{
204
187
current_target_compatible = or_exprt (
205
188
current_target_compatible,
206
- target-> compatible_expression (* called_target));
189
+ target. generate_compatibility_check ( called_target));
207
190
}
208
191
}
209
192
if (first_clause)
@@ -213,10 +196,7 @@ exprt assigns_clauset::compatible_expression(
213
196
}
214
197
else
215
198
{
216
- exprt::operandst conjuncts;
217
- conjuncts.push_back (result);
218
- conjuncts.push_back (current_target_compatible);
219
- result = conjunction (conjuncts);
199
+ result = and_exprt (result, current_target_compatible);
220
200
}
221
201
}
222
202
0 commit comments