@@ -22,7 +22,10 @@ Date: July 2021
22
22
assigns_clauset::targett::targett (
23
23
const assigns_clauset &parent,
24
24
const exprt &expr)
25
- : expr(address_of_exprt(expr)), id(expr.id()), parent(parent)
25
+ : expr(expr),
26
+ id(expr.id()),
27
+ object_expr(address_of_exprt(normalize(expr))),
28
+ parent(parent)
26
29
{
27
30
}
28
31
@@ -38,18 +41,20 @@ exprt assigns_clauset::targett::normalize(const exprt &expr)
38
41
return to_index_expr (object).array ();
39
42
}
40
43
41
- exprt assigns_clauset::targett::generate_alias_check (const exprt &lhs) const
44
+ exprt assigns_clauset::targett::generate_containment_check (
45
+ const exprt &lhs) const
42
46
{
43
47
exprt::operandst condition;
44
48
const auto lhs_ptr =
45
49
(lhs.id () == ID_address_of) ? lhs : address_of_exprt (lhs);
46
50
47
51
// __CPROVER_w_ok(target, sizeof(target))
48
52
condition.push_back (w_ok_exprt (
49
- expr, size_of_expr (dereference_exprt (expr).type (), parent.ns ).value ()));
53
+ object_expr,
54
+ size_of_expr (dereference_exprt (object_expr).type (), parent.ns ).value ()));
50
55
51
56
// __CPROVER_same_object(lhs, target)
52
- condition.push_back (same_object (lhs_ptr, expr ));
57
+ condition.push_back (same_object (lhs_ptr, object_expr ));
53
58
54
59
// If assigns target was a dereference, comparing objects is enough
55
60
if (id == ID_dereference)
@@ -58,7 +63,7 @@ exprt assigns_clauset::targett::generate_alias_check(const exprt &lhs) const
58
63
}
59
64
60
65
const auto lhs_offset = pointer_offset (lhs_ptr);
61
- const auto own_offset = pointer_offset (expr );
66
+ const auto own_offset = pointer_offset (object_expr );
62
67
63
68
// __CPROVER_offset(lhs) >= __CPROVER_offset(target)
64
69
condition.push_back (binary_relation_exprt (lhs_offset, ID_ge, own_offset));
@@ -70,7 +75,7 @@ exprt assigns_clauset::targett::generate_alias_check(const exprt &lhs) const
70
75
71
76
const exprt own_region = plus_exprt (
72
77
typecast_exprt::conditional_cast (
73
- size_of_expr (dereference_exprt (expr ).type (), parent.ns ).value (),
78
+ size_of_expr (dereference_exprt (object_expr ).type (), parent.ns ).value (),
74
79
own_offset.type ()),
75
80
own_offset);
76
81
@@ -81,12 +86,6 @@ exprt assigns_clauset::targett::generate_alias_check(const exprt &lhs) const
81
86
return conjunction (condition);
82
87
}
83
88
84
- exprt assigns_clauset::targett::generate_compatibility_check (
85
- const assigns_clauset::targett &other_target) const
86
- {
87
- return same_object (other_target.expr , expr);
88
- }
89
-
90
89
assigns_clauset::assigns_clauset (
91
90
const exprt &expr,
92
91
const messaget &log,
@@ -101,8 +100,7 @@ assigns_clauset::assigns_clauset(
101
100
102
101
void assigns_clauset::add_target (const exprt &target_expr)
103
102
{
104
- auto insertion_succeeded =
105
- targets.emplace (*this , targett::normalize (target_expr)).second ;
103
+ auto insertion_succeeded = targets.emplace (*this , target_expr).second ;
106
104
107
105
if (!insertion_succeeded)
108
106
{
@@ -117,87 +115,54 @@ goto_programt assigns_clauset::generate_havoc_code() const
117
115
{
118
116
modifiest modifies;
119
117
for (const auto &target : targets)
120
- modifies.insert (to_address_of_expr ( target.expr ) .object ());
118
+ modifies.insert (target.object_expr .object ());
121
119
122
120
goto_programt havoc_statements;
123
121
append_havoc_code (expr.source_location (), modifies, havoc_statements);
124
122
return havoc_statements;
125
123
}
126
124
127
- exprt assigns_clauset::generate_alias_check (const exprt &lhs) const
125
+ exprt assigns_clauset::generate_containment_check (const exprt &lhs) const
128
126
{
129
127
// If write set is empty, no assignment is allowed.
130
128
if (targets.empty ())
131
- {
132
129
return false_exprt ();
133
- }
134
130
135
131
exprt::operandst condition;
136
132
for (const auto &target : targets)
137
133
{
138
- condition.push_back (target.generate_alias_check (lhs));
134
+ condition.push_back (target.generate_containment_check (lhs));
139
135
}
140
136
return disjunction (condition);
141
137
}
142
138
143
- exprt assigns_clauset::generate_compatibility_check (
144
- const assigns_clauset &called_assigns ) const
139
+ exprt assigns_clauset::generate_subset_check (
140
+ const assigns_clauset &subassigns ) const
145
141
{
146
- if (called_assigns.targets .empty ())
147
- {
142
+ if (subassigns.targets .empty ())
148
143
return true_exprt ();
149
- }
150
144
151
- bool first_clause = true ;
152
145
exprt result = true_exprt ();
153
- for (const auto &called_target : called_assigns .targets )
146
+ for (const auto &subtarget : subassigns .targets )
154
147
{
155
- bool first_iter = true ;
156
- exprt current_target_compatible = false_exprt ();
148
+ // TODO: Optimize the implication generated due to the validity check.
149
+ // In some cases, e.g. when `subtarget` is known to be `NULL`,
150
+ // the implication can be skipped entirely. See #6105 for more details.
151
+ auto validity_check =
152
+ w_ok_exprt (subtarget.object_expr , from_integer (0 , unsigned_int_type ()));
153
+
154
+ exprt::operandst current_subtarget_found_conditions;
157
155
for (const auto &target : targets)
158
156
{
159
- if (first_iter)
160
- {
161
- // TODO: Optimize the validation below and remove code duplication
162
- // See GitHub issue #6105 for further details
163
-
164
- // Validating the called target through __CPROVER_w_ok() is
165
- // only useful when the called target is a dereference
166
- const auto &called_target_ptr = called_target.expr ;
167
- if (
168
- to_address_of_expr (called_target_ptr).object ().id () == ID_dereference)
169
- {
170
- // or_exprt is short-circuited, therefore
171
- // target.generate_compatibility_check(*called_target) would not be
172
- // checked on invalid called_targets.
173
- current_target_compatible = or_exprt (
174
- not_exprt (w_ok_exprt (
175
- called_target_ptr, from_integer (0 , unsigned_int_type ()))),
176
- target.generate_compatibility_check (called_target));
177
- }
178
- else
179
- {
180
- current_target_compatible =
181
- target.generate_compatibility_check (called_target);
182
- }
183
- first_iter = false ;
184
- }
185
- else
186
- {
187
- current_target_compatible = or_exprt (
188
- current_target_compatible,
189
- target.generate_compatibility_check (called_target));
190
- }
191
- }
192
- if (first_clause)
193
- {
194
- result = current_target_compatible;
195
- first_clause = false ;
196
- }
197
- else
198
- {
199
- result = and_exprt (result, current_target_compatible);
157
+ current_subtarget_found_conditions.push_back (
158
+ target.generate_containment_check (subtarget.expr ));
200
159
}
160
+
161
+ auto current_subtarget_found = or_exprt (
162
+ not_exprt (validity_check),
163
+ disjunction (current_subtarget_found_conditions));
164
+
165
+ result = and_exprt (result, current_subtarget_found);
201
166
}
202
167
203
168
return result;
0 commit comments