Skip to content

Commit fd8af8a

Browse files
authored
Merge pull request #5644 from jezhiggins/abstract_environmentt-eval
abstract_environmentt::eval rework
2 parents b4427d1 + 7ead4af commit fd8af8a

25 files changed

+327
-249
lines changed
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
CORE
2+
union.c
3+
--variable-sensitivity --verify
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^\[main.assertion.1\] line 13 x.a==0: UNKNOWN$
7+
^\[main.assertion.2\] line 14 x.a==1: UNKNOWN$
8+
^\[main.assertion.3\] line 15 x.b==0: UNKNOWN$
9+
^\[main.assertion.4\] line 16 x.b==1: UNKNOWN$
10+
^\[main.assertion.5\] line 19 x.a==0: UNKNOWN$
11+
^\[main.assertion.6\] line 20 x.a==1: UNKNOWN$
12+
^\[main.assertion.7\] line 21 x.b==0: UNKNOWN$
13+
^\[main.assertion.8\] line 22 x.b==1: UNKNOWN$
14+
--
15+
^warning: ignoring
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#include <assert.h>
2+
3+
int main(int argc, char *argv[])
4+
{
5+
// Test if we can represent constant structs
6+
union union_struct {
7+
int a;
8+
int b;
9+
};
10+
11+
union union_struct x = {0};
12+
x.a = 0;
13+
__CPROVER_assert(x.a == 0, "x.a==0");
14+
__CPROVER_assert(x.a == 1, "x.a==1");
15+
__CPROVER_assert(x.b == 0, "x.b==0");
16+
__CPROVER_assert(x.b == 1, "x.b==1");
17+
18+
x.b = 1;
19+
__CPROVER_assert(x.a == 0, "x.a==0");
20+
__CPROVER_assert(x.a == 1, "x.a==1");
21+
__CPROVER_assert(x.b == 0, "x.b==0");
22+
__CPROVER_assert(x.b == 1, "x.b==1");
23+
24+
return 0;
25+
}

src/analyses/variable-sensitivity/abstract_enviroment.cpp

Lines changed: 30 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@
2727
# include <iostream>
2828
#endif
2929

30+
std::vector<abstract_object_pointert> eval_operands(
31+
const exprt &expr,
32+
const abstract_environmentt &env,
33+
const namespacet &ns);
34+
3035
abstract_object_pointert
3136
abstract_environmentt::eval(const exprt &expr, const namespacet &ns) const
3237
{
@@ -51,14 +56,15 @@ abstract_environmentt::eval(const exprt &expr, const namespacet &ns) const
5156
return found_symbol_value;
5257
}
5358
}
54-
else if(simplified_id == ID_member)
59+
else if(
60+
simplified_id == ID_member || simplified_id == ID_index ||
61+
simplified_id == ID_dereference)
5562
{
56-
member_exprt member_expr(to_member_expr(simplified_expr));
63+
auto access_expr = simplified_expr;
64+
auto target = eval(access_expr.operands()[0], ns);
5765

58-
const exprt &parent = member_expr.compound();
59-
60-
abstract_object_pointert parent_abstract_object = eval(parent, ns);
61-
return parent_abstract_object->read(*this, member_expr, ns);
66+
return target->expression_transform(
67+
access_expr, eval_operands(access_expr, *this, ns), *this, ns);
6268
}
6369
else if(simplified_id == ID_address_of)
6470
{
@@ -68,35 +74,12 @@ abstract_environmentt::eval(const exprt &expr, const namespacet &ns) const
6874
// Store the abstract object in the pointer
6975
return pointer_object;
7076
}
71-
else if(simplified_id == ID_dereference)
72-
{
73-
dereference_exprt dereference(to_dereference_expr(simplified_expr));
74-
abstract_object_pointert pointer_abstract_object =
75-
eval(dereference.pointer(), ns);
76-
77-
return pointer_abstract_object->read(*this, nil_exprt(), ns);
78-
}
79-
else if(simplified_id == ID_index)
80-
{
81-
index_exprt index_expr(to_index_expr(simplified_expr));
82-
abstract_object_pointert array_abstract_object =
83-
eval(index_expr.array(), ns);
84-
85-
return array_abstract_object->read(*this, index_expr, ns);
86-
}
87-
else if(simplified_id == ID_array)
77+
else if(
78+
simplified_id == ID_array || simplified_id == ID_struct ||
79+
simplified_id == ID_constant)
8880
{
8981
return abstract_object_factory(simplified_expr.type(), simplified_expr, ns);
9082
}
91-
else if(simplified_id == ID_struct)
92-
{
93-
return abstract_object_factory(simplified_expr.type(), simplified_expr, ns);
94-
}
95-
else if(simplified_id == ID_constant)
96-
{
97-
return abstract_object_factory(
98-
simplified_expr.type(), to_constant_expr(simplified_expr), ns);
99-
}
10083
else
10184
{
10285
// No special handling required by the abstract environment
@@ -448,14 +431,8 @@ abstract_object_pointert abstract_environmentt::eval_expression(
448431
abstract_object_pointert eval_obj =
449432
abstract_object_factory(e.type(), ns, true);
450433

451-
std::vector<abstract_object_pointert> operands;
452-
453-
for(const auto &op : e.operands())
454-
{
455-
operands.push_back(eval(op, ns));
456-
}
457-
458-
return eval_obj->expression_transform(e, operands, *this, ns);
434+
return eval_obj->expression_transform(
435+
e, eval_operands(e, *this, ns), *this, ns);
459436
}
460437

461438
void abstract_environmentt::erase(const symbol_exprt &expr)
@@ -527,3 +504,16 @@ abstract_environmentt::gather_statistics(const namespacet &ns) const
527504
}
528505
return statistics;
529506
}
507+
508+
std::vector<abstract_object_pointert> eval_operands(
509+
const exprt &expr,
510+
const abstract_environmentt &env,
511+
const namespacet &ns)
512+
{
513+
std::vector<abstract_object_pointert> operands;
514+
515+
for(const auto &op : expr.operands())
516+
operands.push_back(env.eval(op, ns));
517+
518+
return operands;
519+
}

src/analyses/variable-sensitivity/abstract_object.cpp

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -136,14 +136,6 @@ abstract_object_pointert abstract_objectt::expression_transform(
136136
return environment.abstract_object_factory(copy.type(), copy, ns);
137137
}
138138

139-
abstract_object_pointert abstract_objectt::read(
140-
const abstract_environmentt &env,
141-
const exprt &specifier,
142-
const namespacet &ns) const
143-
{
144-
return shared_from_this();
145-
}
146-
147139
abstract_object_pointert abstract_objectt::write(
148140
abstract_environmentt &environment,
149141
const namespacet &ns,

src/analyses/variable-sensitivity/abstract_object.h

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -177,23 +177,6 @@ class abstract_objectt : public std::enable_shared_from_this<abstract_objectt>
177177
/// that allows an object to be built from a value.
178178
virtual exprt to_constant() const;
179179

180-
/**
181-
* A helper function to evaluate an abstract object contained
182-
* within a container object. More precise abstractions may override this
183-
* to return more precise results.
184-
*
185-
* \param env the abstract environment
186-
* \param specifier a modifier expression, such as an array index or field
187-
* specifier used to indicate access to a specific component
188-
* \param ns the current namespace
189-
*
190-
* \return the abstract_objectt representing the value of the read component.
191-
*/
192-
virtual abstract_object_pointert read(
193-
const abstract_environmentt &env,
194-
const exprt &specifier,
195-
const namespacet &ns) const;
196-
197180
/**
198181
* A helper function to evaluate writing to a component of an
199182
* abstract object. More precise abstractions may override this to

src/analyses/variable-sensitivity/array_abstract_object.cpp

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,19 @@ array_abstract_objectt::array_abstract_objectt(
3535
PRECONDITION(e.type().id() == ID_array);
3636
}
3737

38-
abstract_object_pointert array_abstract_objectt::read(
39-
const abstract_environmentt &env,
40-
const exprt &specifier,
38+
abstract_object_pointert array_abstract_objectt::expression_transform(
39+
const exprt &expr,
40+
const std::vector<abstract_object_pointert> &operands,
41+
const abstract_environmentt &environment,
4142
const namespacet &ns) const
4243
{
43-
return this->read_index(env, to_index_expr(specifier), ns);
44+
if(expr.id() == ID_index)
45+
{
46+
return read_index(environment, to_index_expr(expr), ns);
47+
}
48+
49+
return abstract_objectt::expression_transform(
50+
expr, operands, environment, ns);
4451
}
4552

4653
abstract_object_pointert array_abstract_objectt::write(

src/analyses/variable-sensitivity/array_abstract_object.h

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -42,21 +42,25 @@ class array_abstract_objectt : public abstract_objectt
4242
const abstract_environmentt &environment,
4343
const namespacet &ns);
4444

45-
/**
46-
* A helper function to evaluate an abstract object contained
47-
* within a container object. More precise abstractions may override this
48-
* to return more precise results.
49-
*
50-
* \param env the abstract environment
51-
* \param specifier a modifier expression, such as an array index or field
52-
* specifier used to indicate access to a specific component
53-
* \param ns the current namespace
54-
*
55-
* \return the abstract_objectt representing the value of the read component.
56-
*/
57-
abstract_object_pointert read(
58-
const abstract_environmentt &env,
59-
const exprt &specifier,
45+
/// Interface for transforms
46+
///
47+
/// \param expr: the expression to evaluate and find the result of it.
48+
/// This will be the symbol referred to be op0()
49+
/// \param operands: an abstract_object (pointer) that represent
50+
/// the possible values of each operand
51+
/// \param environment: the abstract environment in which the
52+
/// expression is being evaluated
53+
/// \param ns: the current variable namespace
54+
///
55+
/// \return Returns the abstract_object representing the result of
56+
/// this expression to the maximum precision available.
57+
///
58+
/// To try and resolve different expressions with the maximum level
59+
/// of precision available.
60+
abstract_object_pointert expression_transform(
61+
const exprt &expr,
62+
const std::vector<abstract_object_pointert> &operands,
63+
const abstract_environmentt &environment,
6064
const namespacet &ns) const override;
6165

6266
/**

src/analyses/variable-sensitivity/context_abstract_object.cpp

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -30,28 +30,6 @@ void context_abstract_objectt::set_not_top_internal()
3030
set_child(child_abstract_object->clear_top());
3131
}
3232

33-
/**
34-
* A helper function to evaluate an abstract object contained
35-
* within a container object. More precise abstractions may override this
36-
* to return more precise results.
37-
*
38-
* \param env the abstract environment
39-
* \param specifier a modifier expression, such as an array index or field
40-
* specifier used to indicate access to a specific component
41-
* \param ns the current namespace
42-
*
43-
* \return the abstract_objectt representing the value of the read component.
44-
* For the dependency context, the operation is simply delegated to the
45-
* child object
46-
*/
47-
abstract_object_pointert context_abstract_objectt::read(
48-
const abstract_environmentt &env,
49-
const exprt &specifier,
50-
const namespacet &ns) const
51-
{
52-
return child_abstract_object->read(env, specifier, ns);
53-
}
54-
5533
/**
5634
* A helper function to evaluate writing to a component of an
5735
* abstract object. More precise abstractions may override this to

src/analyses/variable-sensitivity/context_abstract_object.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -107,11 +107,6 @@ class context_abstract_objectt : public abstract_objectt
107107
void set_top_internal() override;
108108
void set_not_top_internal() override;
109109

110-
abstract_object_pointert read(
111-
const abstract_environmentt &env,
112-
const exprt &specifier,
113-
const namespacet &ns) const override;
114-
115110
abstract_object_pointert write(
116111
abstract_environmentt &environment,
117112
const namespacet &ns,

src/analyses/variable-sensitivity/pointer_abstract_object.cpp

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,19 @@ pointer_abstract_objectt::pointer_abstract_objectt(
3636
PRECONDITION(e.type().id() == ID_pointer);
3737
}
3838

39-
abstract_object_pointert pointer_abstract_objectt::read(
40-
const abstract_environmentt &env,
41-
const exprt &specifier,
39+
abstract_object_pointert pointer_abstract_objectt::expression_transform(
40+
const exprt &expr,
41+
const std::vector<abstract_object_pointert> &operands,
42+
const abstract_environmentt &environment,
4243
const namespacet &ns) const
4344
{
44-
return read_dereference(env, ns);
45+
if(expr.id() == ID_dereference)
46+
{
47+
return read_dereference(environment, ns);
48+
}
49+
50+
return abstract_objectt::expression_transform(
51+
expr, operands, environment, ns);
4552
}
4653

4754
abstract_object_pointert pointer_abstract_objectt::write(

src/analyses/variable-sensitivity/pointer_abstract_object.h

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,27 @@ class pointer_abstract_objectt : public abstract_objectt
3333
/// \param bottom: is the abstract_object starting as bottom
3434
pointer_abstract_objectt(const typet &type, bool top, bool bottom);
3535

36+
/// Interface for transforms
37+
///
38+
/// \param expr: the expression to evaluate and find the result of it.
39+
/// This will be the symbol referred to be op0()
40+
/// \param operands: an abstract_object (pointer) that represent
41+
/// the possible values of each operand
42+
/// \param environment: the abstract environment in which the
43+
/// expression is being evaluated
44+
/// \param ns: the current variable namespace
45+
///
46+
/// \return Returns the abstract_object representing the result of
47+
/// this expression to the maximum precision available.
48+
///
49+
/// To try and resolve different expressions with the maximum level
50+
/// of precision available.
51+
abstract_object_pointert expression_transform(
52+
const exprt &expr,
53+
const std::vector<abstract_object_pointert> &operands,
54+
const abstract_environmentt &environment,
55+
const namespacet &ns) const override;
56+
3657
/// \param expr: the expression to use as the starting pointer for
3758
/// an abstract object
3859
/// \param environment: the environment in which the pointer is being
@@ -43,23 +64,6 @@ class pointer_abstract_objectt : public abstract_objectt
4364
const abstract_environmentt &environment,
4465
const namespacet &ns);
4566

46-
/**
47-
* A helper function to evaluate an abstract object contained
48-
* within a container object. More precise abstractions may override this
49-
* to return more precise results.
50-
*
51-
* \param env the abstract environment
52-
* \param specifier a modifier expression, such as an array index or field
53-
* specifier used to indicate access to a specific component
54-
* \param ns the current namespace
55-
*
56-
* \return the abstract_objectt representing the value of the read component.
57-
*/
58-
abstract_object_pointert read(
59-
const abstract_environmentt &env,
60-
const exprt &specifier,
61-
const namespacet &ns) const override;
62-
6367
/**
6468
* A helper function to evaluate writing to a component of an
6569
* abstract object. More precise abstractions may override this to

src/analyses/variable-sensitivity/struct_abstract_object.cpp

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,19 @@ struct_abstract_objectt::struct_abstract_objectt(
3737
PRECONDITION(ns.follow(e.type()).id() == ID_struct);
3838
}
3939

40-
abstract_object_pointert struct_abstract_objectt::read(
41-
const abstract_environmentt &env,
42-
const exprt &specifier,
40+
abstract_object_pointert struct_abstract_objectt::expression_transform(
41+
const exprt &expr,
42+
const std::vector<abstract_object_pointert> &operands,
43+
const abstract_environmentt &environment,
4344
const namespacet &ns) const
4445
{
45-
return this->read_component(env, to_member_expr(specifier), ns);
46+
if(expr.id() == ID_member)
47+
{
48+
return read_component(environment, to_member_expr(expr), ns);
49+
}
50+
51+
return abstract_objectt::expression_transform(
52+
expr, operands, environment, ns);
4653
}
4754

4855
abstract_object_pointert struct_abstract_objectt::write(

0 commit comments

Comments
 (0)