@@ -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
+ : address(address_of_exprt(normalize(expr))),
26
+ expr(expr),
27
+ id(expr.id()),
28
+ parent(parent)
26
29
{
27
30
}
28
31
@@ -38,39 +41,40 @@ 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 address_of_exprt &lhs_address) const
42
46
{
43
47
exprt::operandst condition;
44
- const auto lhs_ptr =
45
- (lhs.id () == ID_address_of) ? lhs : address_of_exprt (lhs);
46
48
47
49
// __CPROVER_w_ok(target, sizeof(target))
48
50
condition.push_back (w_ok_exprt (
49
- expr, size_of_expr (dereference_exprt (expr).type (), parent.ns ).value ()));
51
+ address,
52
+ size_of_expr (dereference_exprt (address).type (), parent.ns ).value ()));
50
53
51
54
// __CPROVER_same_object(lhs, target)
52
- condition.push_back (same_object (lhs_ptr, expr ));
55
+ condition.push_back (same_object (lhs_address, address ));
53
56
54
57
// If assigns target was a dereference, comparing objects is enough
55
58
if (id == ID_dereference)
56
59
{
57
60
return conjunction (condition);
58
61
}
59
62
60
- const auto lhs_offset = pointer_offset (lhs_ptr );
61
- const auto own_offset = pointer_offset (expr );
63
+ const auto lhs_offset = pointer_offset (lhs_address );
64
+ const auto own_offset = pointer_offset (address );
62
65
63
66
// __CPROVER_offset(lhs) >= __CPROVER_offset(target)
64
67
condition.push_back (binary_relation_exprt (lhs_offset, ID_ge, own_offset));
65
68
66
69
const auto lhs_region = plus_exprt (
67
70
typecast_exprt::conditional_cast (
68
- size_of_expr (lhs.type (), parent.ns ).value (), lhs_offset.type ()),
71
+ size_of_expr (lhs_address.object ().type (), parent.ns ).value (),
72
+ lhs_offset.type ()),
69
73
lhs_offset);
70
74
71
75
const exprt own_region = plus_exprt (
72
76
typecast_exprt::conditional_cast (
73
- size_of_expr (dereference_exprt (expr ).type (), parent.ns ).value (),
77
+ size_of_expr (address. object ( ).type (), parent.ns ).value (),
74
78
own_offset.type ()),
75
79
own_offset);
76
80
@@ -81,12 +85,6 @@ exprt assigns_clauset::targett::generate_alias_check(const exprt &lhs) const
81
85
return conjunction (condition);
82
86
}
83
87
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
88
assigns_clauset::assigns_clauset (
91
89
const exprt &expr,
92
90
const messaget &log,
@@ -101,8 +99,7 @@ assigns_clauset::assigns_clauset(
101
99
102
100
void assigns_clauset::add_target (const exprt &target_expr)
103
101
{
104
- auto insertion_succeeded =
105
- targets.emplace (*this , targett::normalize (target_expr)).second ;
102
+ auto insertion_succeeded = targets.emplace (*this , target_expr).second ;
106
103
107
104
if (!insertion_succeeded)
108
105
{
@@ -117,87 +114,56 @@ goto_programt assigns_clauset::generate_havoc_code() const
117
114
{
118
115
modifiest modifies;
119
116
for (const auto &target : targets)
120
- modifies.insert (to_address_of_expr ( target.expr ) .object ());
117
+ modifies.insert (target.address .object ());
121
118
122
119
goto_programt havoc_statements;
123
120
append_havoc_code (expr.source_location (), modifies, havoc_statements);
124
121
return havoc_statements;
125
122
}
126
123
127
- exprt assigns_clauset::generate_alias_check (const exprt &lhs) const
124
+ exprt assigns_clauset::generate_containment_check (const exprt &lhs) const
128
125
{
129
126
// If write set is empty, no assignment is allowed.
130
127
if (targets.empty ())
131
- {
132
128
return false_exprt ();
133
- }
129
+
130
+ const auto lhs_address = address_of_exprt (targett::normalize (lhs));
134
131
135
132
exprt::operandst condition;
136
133
for (const auto &target : targets)
137
134
{
138
- condition.push_back (target.generate_alias_check (lhs ));
135
+ condition.push_back (target.generate_containment_check (lhs_address ));
139
136
}
140
137
return disjunction (condition);
141
138
}
142
139
143
- exprt assigns_clauset::generate_compatibility_check (
144
- const assigns_clauset &called_assigns ) const
140
+ exprt assigns_clauset::generate_subset_check (
141
+ const assigns_clauset &subassigns ) const
145
142
{
146
- if (called_assigns.targets .empty ())
147
- {
143
+ if (subassigns.targets .empty ())
148
144
return true_exprt ();
149
- }
150
145
151
- bool first_clause = true ;
152
146
exprt result = true_exprt ();
153
- for (const auto &called_target : called_assigns .targets )
147
+ for (const auto &subtarget : subassigns .targets )
154
148
{
155
- bool first_iter = true ;
156
- exprt current_target_compatible = false_exprt ();
149
+ // TODO: Optimize the implication generated due to the validity check.
150
+ // In some cases, e.g. when `subtarget` is known to be `NULL`,
151
+ // the implication can be skipped entirely. See #6105 for more details.
152
+ auto validity_check =
153
+ w_ok_exprt (subtarget.address , from_integer (0 , unsigned_int_type ()));
154
+
155
+ exprt::operandst current_subtarget_found_conditions;
157
156
for (const auto &target : targets)
158
157
{
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);
158
+ current_subtarget_found_conditions.push_back (
159
+ target.generate_containment_check (subtarget.address ));
200
160
}
161
+
162
+ auto current_subtarget_found = or_exprt (
163
+ not_exprt (validity_check),
164
+ disjunction (current_subtarget_found_conditions));
165
+
166
+ result = and_exprt (result, current_subtarget_found);
201
167
}
202
168
203
169
return result;
0 commit comments