Skip to content

Commit ff6685f

Browse files
committed
Value set dereferencing: do not treat struct prefixes as equal
Two distinct struct types cannot be cast between, even when one is a prefix of the other. Value set dereferencing taking this approach just resulted in propositional encoding producing a warning about invalid type casts.
1 parent 22d25d1 commit ff6685f

File tree

9 files changed

+101
-59
lines changed

9 files changed

+101
-59
lines changed

jbmc/regression/jbmc/simplify-classid-of-interface/test_no_simplify_vccs.desc

Lines changed: 0 additions & 11 deletions
This file was deleted.

regression/cbmc/struct2/main.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
struct T
2+
{
3+
// intentionally empty to trigger is_prefix_of code (empty structs, however,
4+
// are a GCC-only feature)
5+
};
6+
7+
struct S
8+
{
9+
struct T t;
10+
int other;
11+
};
12+
13+
void foo(struct S s2)
14+
{
15+
struct T *p = &s2.t;
16+
struct T t2 = *p;
17+
__CPROVER_assert(0, "");
18+
}
19+
20+
int main()
21+
{
22+
struct S s;
23+
foo(s);
24+
}

regression/cbmc/struct2/test.desc

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
CORE gcc-only no-new-smt
2+
main.c
3+
4+
^VERIFICATION FAILED$
5+
^EXIT=10$
6+
^SIGNAL=0$
7+
--
8+
^warning: ignoring
9+
--
10+
This test must not generate a warning about typecasts (between different struct
11+
types) being ignored.

regression/cbmc/struct5/main.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#include <assert.h>
2+
3+
struct a
4+
{
5+
int x;
6+
};
7+
struct b
8+
{
9+
struct a p;
10+
int y;
11+
};
12+
13+
int f00(struct a *ptr)
14+
{
15+
return ptr->x;
16+
}
17+
18+
int main()
19+
{
20+
struct b z = {{1}, 2};
21+
22+
assert(&z == &(z.p));
23+
assert(&z == &(z.p.x));
24+
25+
assert(f00(&z) == z.p.x);
26+
27+
return 0;
28+
}

regression/cbmc/struct5/test.desc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
main.c
3+
4+
^VERIFICATION SUCCESSFUL$
5+
^EXIT=0$
6+
^SIGNAL=0$
7+
--
8+
^warning: ignoring

src/cprover/may_alias.cpp

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,34 @@ bool is_object_field_element(const exprt &expr)
7171
return false;
7272
}
7373

74+
/// Returns true if struct \p a is a prefix of \p b, i.e., if this struct has
75+
/// n components then the component types and names of this struct must match
76+
/// the first n components of \p b.
77+
/// \param a: Struct type that may be a prefix.
78+
/// \param b: Struct type to compare with.
79+
static bool struct_is_prefix_of(const struct_typet &a, const struct_typet &b)
80+
{
81+
const struct_typet::componentst &ot_components = b.components();
82+
const struct_typet::componentst &tt_components = a.components();
83+
84+
if(ot_components.size() < tt_components.size())
85+
return false;
86+
87+
struct_typet::componentst::const_iterator ot_it = ot_components.begin();
88+
89+
for(const auto &tt_c : tt_components)
90+
{
91+
if(ot_it->type() != tt_c.type() || ot_it->get_name() != tt_c.get_name())
92+
{
93+
return false; // they just don't match
94+
}
95+
96+
ot_it++;
97+
}
98+
99+
return true; // ok, a is a prefix of b
100+
}
101+
74102
bool prefix_of(const typet &a, const typet &b, const namespacet &ns)
75103
{
76104
if(a == b)
@@ -88,7 +116,8 @@ bool prefix_of(const typet &a, const typet &b, const namespacet &ns)
88116
const auto &a_struct = to_struct_type(a);
89117
const auto &b_struct = to_struct_type(b);
90118

91-
return a_struct.is_prefix_of(b_struct) || b_struct.is_prefix_of(a_struct);
119+
return struct_is_prefix_of(a_struct, b_struct) ||
120+
struct_is_prefix_of(b_struct, a_struct);
92121
}
93122

94123
static std::optional<object_address_exprt> find_object(const exprt &expr)

src/pointer-analysis/value_set_dereference.cpp

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -372,22 +372,6 @@ bool value_set_dereferencet::dereference_type_compare(
372372
if(object_type == dereference_type)
373373
return true; // ok, they just match
374374

375-
// check for struct prefixes
376-
const typet &ot_base = object_type.id() == ID_struct_tag
377-
? ns.follow_tag(to_struct_tag_type(object_type))
378-
: object_type;
379-
const typet &dt_base = dereference_type.id() == ID_struct_tag
380-
? ns.follow_tag(to_struct_tag_type(dereference_type))
381-
: dereference_type;
382-
383-
if(ot_base.id()==ID_struct &&
384-
dt_base.id()==ID_struct)
385-
{
386-
if(to_struct_type(dt_base).is_prefix_of(
387-
to_struct_type(ot_base)))
388-
return true; // ok, dt is a prefix of ot
389-
}
390-
391375
// we are generous about code pointers
392376
if(dereference_type.id()==ID_code &&
393377
object_type.id()==ID_code)

src/util/std_types.cpp

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -112,35 +112,6 @@ struct_typet::get_base(const irep_idt &id) const
112112
return {};
113113
}
114114

115-
/// Returns true if the struct is a prefix of \a other, i.e., if this struct
116-
/// has n components then the component types and names of this struct must
117-
/// match the first n components of \a other struct.
118-
/// \param other: Struct type to compare with.
119-
bool struct_typet::is_prefix_of(const struct_typet &other) const
120-
{
121-
const componentst &ot_components=other.components();
122-
const componentst &tt_components=components();
123-
124-
if(ot_components.size()<
125-
tt_components.size())
126-
return false;
127-
128-
componentst::const_iterator
129-
ot_it=ot_components.begin();
130-
131-
for(const auto &tt_c : tt_components)
132-
{
133-
if(ot_it->type() != tt_c.type() || ot_it->get_name() != tt_c.get_name())
134-
{
135-
return false; // they just don't match
136-
}
137-
138-
ot_it++;
139-
}
140-
141-
return true; // ok, *this is a prefix of ot
142-
}
143-
144115
/// Returns true if the type is a reference.
145116
bool is_reference(const typet &type)
146117
{

src/util/std_types.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -239,8 +239,6 @@ class struct_typet:public struct_union_typet
239239
{
240240
}
241241

242-
bool is_prefix_of(const struct_typet &other) const;
243-
244242
/// A struct may be a class, where members may have access restrictions.
245243
bool is_class() const
246244
{

0 commit comments

Comments
 (0)