Skip to content

Commit aae4b10

Browse files
smowtontautschnig
authored andcommitted
Remove composite object from the constant propagator when a field is updated
Otherwise e.g. in "memset2" we had the whole object being initialised with "{0, 0}" (which is stored in const prop and then expanded to individual fields), then later any operation that needed the whole-struct representation (such as the memset-of-one-field in that test, which expanded to "whole_struct = byte_update(whole_struct, offset, int, 0)") would get the whole-struct definition stored in const-prop, disregarding any intermediate updates that were able to directly reference a single field. This avoids having two different versions of a symbol (the field-of-composite and the indivisible field versions) in the most direct way possible.
1 parent 5e83872 commit aae4b10

File tree

6 files changed

+92
-15
lines changed

6 files changed

+92
-15
lines changed

src/goto-symex/field_sensitivity.cpp

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -167,15 +167,17 @@ exprt field_sensitivityt::get_fields(
167167
void field_sensitivityt::field_assignments(
168168
const namespacet &ns,
169169
goto_symex_statet &state,
170-
const exprt &lhs,
171-
symex_targett &target)
170+
const ssa_exprt &lhs,
171+
symex_targett &target,
172+
bool allow_pointer_unsoundness)
172173
{
173174
exprt lhs_fs = lhs;
174175
apply(ns, state, lhs_fs, false);
175176

176177
bool run_apply_bak = run_apply;
177178
run_apply = false;
178-
field_assignments_rec(ns, state, lhs_fs, lhs, target);
179+
field_assignments_rec(
180+
ns, state, lhs_fs, lhs, target, allow_pointer_unsoundness);
179181
run_apply = run_apply_bak;
180182
}
181183

@@ -188,12 +190,14 @@ void field_sensitivityt::field_assignments(
188190
/// \param lhs_fs: expanded symbol
189191
/// \param lhs: non-expanded symbol
190192
/// \param target: symbolic execution equation store
193+
/// \param allow_pointer_unsoundness: allow pointer unsoundness
191194
void field_sensitivityt::field_assignments_rec(
192195
const namespacet &ns,
193196
goto_symex_statet &state,
194197
const exprt &lhs_fs,
195198
const exprt &lhs,
196-
symex_targett &target)
199+
symex_targett &target,
200+
bool allow_pointer_unsoundness)
197201
{
198202
if(lhs == lhs_fs)
199203
return;
@@ -203,7 +207,8 @@ void field_sensitivityt::field_assignments_rec(
203207
simplify(ssa_rhs, ns);
204208

205209
ssa_exprt ssa_lhs = to_ssa_expr(lhs_fs);
206-
state.assignment(ssa_lhs, ssa_rhs, ns, true, true);
210+
state.assignment(
211+
ssa_lhs, ssa_rhs, ns, true, true, allow_pointer_unsoundness);
207212

208213
// do the assignment
209214
target.assignment(
@@ -230,7 +235,8 @@ void field_sensitivityt::field_assignments_rec(
230235
const member_exprt member_rhs(lhs, comp.get_name(), comp.type());
231236
const exprt &member_lhs = *fs_it;
232237

233-
field_assignments_rec(ns, state, member_lhs, member_rhs, target);
238+
field_assignments_rec(
239+
ns, state, member_lhs, member_rhs, target, allow_pointer_unsoundness);
234240
++fs_it;
235241
}
236242
}
@@ -248,7 +254,8 @@ void field_sensitivityt::field_assignments_rec(
248254
const index_exprt index_rhs(lhs, from_integer(i, index_type()));
249255
const exprt &index_lhs = *fs_it;
250256

251-
field_assignments_rec(ns, state, index_lhs, index_rhs, target);
257+
field_assignments_rec(
258+
ns, state, index_lhs, index_rhs, target, allow_pointer_unsoundness);
252259
++fs_it;
253260
}
254261
}
@@ -261,7 +268,8 @@ void field_sensitivityt::field_assignments_rec(
261268
exprt::operandst::const_iterator fs_it = lhs_fs.operands().begin();
262269
for(const exprt &op : lhs.operands())
263270
{
264-
field_assignments_rec(ns, state, *fs_it, op, target);
271+
field_assignments_rec(
272+
ns, state, *fs_it, op, target, allow_pointer_unsoundness);
265273
++fs_it;
266274
}
267275
}

src/goto-symex/field_sensitivity.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,13 @@ class field_sensitivityt
2727
/// \param state: symbolic execution state
2828
/// \param lhs: non-expanded symbol
2929
/// \param target: symbolic execution equation store
30+
/// \param allow_pointer_unsoundness: allow pointer unsoundness
3031
void field_assignments(
3132
const namespacet &ns,
3233
goto_symex_statet &state,
33-
const exprt &lhs,
34-
symex_targett &target);
34+
const ssa_exprt &lhs,
35+
symex_targett &target,
36+
bool allow_pointer_unsoundness);
3537

3638
/// Turn an expression \p expr into a field-sensitive SSA expression.
3739
/// Field-sensitive SSA expressions have individual symbols for each
@@ -81,7 +83,8 @@ class field_sensitivityt
8183
goto_symex_statet &state,
8284
const exprt &lhs_fs,
8385
const exprt &lhs,
84-
symex_targett &target);
86+
symex_targett &target,
87+
bool allow_pointer_unsoundness);
8588
};
8689

8790
#endif // CPROVER_GOTO_SYMEX_FIELD_SENSITIVITY_H

src/goto-symex/goto_symex_state.cpp

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ void goto_symex_statet::assignment(
170170
{
171171
DATA_INVARIANT(!check_renaming_l1(lhs), "lhs renaming failed on l1");
172172
}
173+
const ssa_exprt l1_lhs = lhs;
173174

174175
#if 0
175176
PRECONDITION(l1_identifier != get_original_name(l1_identifier)
@@ -221,11 +222,23 @@ void goto_symex_statet::assignment(
221222
value_set.assign(l1_lhs, l1_rhs, ns, rhs_is_simplified, is_shared);
222223
}
223224

224-
#if 0
225+
if(field_sensitivityt::is_divisible(l1_lhs))
226+
{
227+
// Split composite symbol lhs into its components
228+
field_sensitivity.field_assignments(
229+
ns, *this, l1_lhs, *symex_target, allow_pointer_unsoundness);
230+
// Erase the composite symbol from our working state. Note that we need to
231+
// have it in the propagation table and the value set while doing the field
232+
// assignments, thus we cannot skip putting it in there above.
233+
propagation.erase(l1_identifier);
234+
value_set.erase_symbol(l1_lhs, ns);
235+
}
236+
237+
#if 0
225238
std::cout << "Assigning " << l1_identifier << '\n';
226239
value_set.output(ns, std::cout);
227240
std::cout << "**********************\n";
228-
#endif
241+
#endif
229242
}
230243

231244
template <levelt level>

src/goto-symex/symex_assign.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -434,8 +434,6 @@ void goto_symext::symex_assign_symbol(
434434
state.source,
435435
assignment_type);
436436

437-
state.field_sensitivity.field_assignments(ns, state, lhs_mod, target);
438-
439437
// Restore the guard
440438
guard.pop_back();
441439
}

src/pointer-analysis/value_set.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1653,3 +1653,46 @@ void value_sett::erase_values_from_entry(
16531653
}
16541654
values.replace(index, std::move(replacement));
16551655
}
1656+
1657+
void value_sett::erase_struct_union_symbol(
1658+
const struct_union_typet &struct_union_type,
1659+
const std::string &erase_prefix,
1660+
const namespacet &ns)
1661+
{
1662+
for(const auto &c : struct_union_type.components())
1663+
{
1664+
const typet &subtype = c.type();
1665+
const irep_idt &name = c.get_name();
1666+
1667+
// ignore methods and padding
1668+
if(subtype.id() == ID_code || c.get_is_padding())
1669+
continue;
1670+
1671+
erase_symbol_rec(subtype, erase_prefix + "." + id2string(name), ns);
1672+
}
1673+
}
1674+
1675+
void value_sett::erase_symbol_rec(
1676+
const typet &type,
1677+
const std::string &erase_prefix,
1678+
const namespacet &ns)
1679+
{
1680+
if(type.id() == ID_struct_tag)
1681+
erase_struct_union_symbol(
1682+
ns.follow_tag(to_struct_tag_type(type)), erase_prefix, ns);
1683+
else if(type.id() == ID_union_tag)
1684+
erase_struct_union_symbol(
1685+
ns.follow_tag(to_union_tag_type(type)), erase_prefix, ns);
1686+
else if(type.id() == ID_array)
1687+
erase_symbol_rec(type.subtype(), erase_prefix + "[]", ns);
1688+
else if(values.has_key(erase_prefix))
1689+
values.erase(erase_prefix);
1690+
}
1691+
1692+
void value_sett::erase_symbol(
1693+
const symbol_exprt &symbol_expr,
1694+
const namespacet &ns)
1695+
{
1696+
erase_symbol_rec(
1697+
symbol_expr.type(), id2string(symbol_expr.get_identifier()), ns);
1698+
}

src/pointer-analysis/value_set.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,8 @@ class value_sett
481481
const irep_idt &index,
482482
const std::unordered_set<exprt, irep_hash> &values_to_erase);
483483

484+
void erase_symbol(const symbol_exprt &symbol_expr, const namespacet &ns);
485+
484486
protected:
485487
/// Reads the set of objects pointed to by `expr`, including making
486488
/// recursive lookups for dereference operations etc.
@@ -515,6 +517,16 @@ class value_sett
515517
const exprt &src,
516518
exprt &dest) const;
517519

520+
void erase_symbol_rec(
521+
const typet &type,
522+
const std::string &erase_prefix,
523+
const namespacet &ns);
524+
525+
void erase_struct_union_symbol(
526+
const struct_union_typet &struct_union_type,
527+
const std::string &erase_prefix,
528+
const namespacet &ns);
529+
518530
// Subclass customisation points:
519531

520532
protected:

0 commit comments

Comments
 (0)