Skip to content

Commit 9f8e155

Browse files
author
thk123
committed
Implementing a write_stack to represent writing to a addressable location
Deals with storing a stack to write to things like: &a[1] &s.comp &a[x] + 1 By building a stack as parsing the expression tree. It does not support pointer arithmetic outside the scope of an array (e.g. within a struct) This will be used to store pointer values. Disabled unit tests since don't have the prerequistes in this branch
1 parent 35c0970 commit 9f8e155

File tree

7 files changed

+987
-0
lines changed

7 files changed

+987
-0
lines changed

src/analyses/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ SRC = ai.cpp \
3838
variable-sensitivity/full_struct_abstract_object.cpp \
3939
variable-sensitivity/constant_array_abstract_object.cpp \
4040
variable-sensitivity/union_abstract_object.cpp \
41+
variable-sensitivity/write_stack.cpp \
42+
variable-sensitivity/write_stack_entry.cpp \
4143
# Empty last line
4244

4345
INCLUDES= -I ..
Lines changed: 260 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,260 @@
1+
/*******************************************************************\
2+
3+
Module: Variable Sensitivity Domain
4+
5+
Author: DiffBlue Limited. All rights reserved.
6+
7+
\*******************************************************************/
8+
9+
/// \file
10+
/// Represents a stack of write operations to an addressable memory
11+
/// location
12+
13+
#include "write_stack.h"
14+
15+
#include <unordered_set>
16+
17+
#include <util/std_expr.h>
18+
#include <util/simplify_expr.h>
19+
20+
/// Build a topstack
21+
write_stackt::write_stackt():
22+
stack(),
23+
top_stack(true)
24+
{}
25+
26+
/// Construct a write stack from an expression
27+
/// \param expr: The expression to represent
28+
/// \param environment: The environment to evaluate any expressions in
29+
/// \param ns: The global namespace
30+
write_stackt::write_stackt(
31+
const exprt &expr,
32+
const abstract_environmentt &environment,
33+
const namespacet &ns)
34+
{
35+
top_stack=false;
36+
if(expr.type().id()==ID_array)
37+
{
38+
// We are assigning an array to a pointer, which is equivalent to assigning
39+
// the first element of that arary
40+
// &(expr)[0]
41+
construct_stack_to_pointer(
42+
address_of_exprt(
43+
index_exprt(
44+
expr, constant_exprt::integer_constant(0))), environment, ns);
45+
}
46+
else
47+
{
48+
construct_stack_to_pointer(expr, environment, ns);
49+
}
50+
}
51+
52+
/// Add to the stack the elements to get to a pointer
53+
/// \param expr: An expression of type pointer to construct the stack to
54+
/// \param environment: The environment to evaluate any expressions in
55+
/// \param ns: The global namespace
56+
void write_stackt::construct_stack_to_pointer(
57+
const exprt &expr,
58+
const abstract_environmentt &environment,
59+
const namespacet &ns)
60+
{
61+
PRECONDITION(expr.type().id()==ID_pointer);
62+
63+
// If we are a pointer to a struct, we do not currently support reading
64+
// writing directly to it so just create a top stack
65+
if(ns.follow(expr.type().subtype()).id()==ID_struct)
66+
{
67+
top_stack=true;
68+
return;
69+
}
70+
71+
if(expr.id()==ID_address_of)
72+
{
73+
// resovle reminder, can either be a symbol, member or index of
74+
// otherwise unsupported
75+
construct_stack_to_lvalue(expr.op0(), environment, ns);
76+
}
77+
else if(expr.id()==ID_plus || expr.id()==ID_minus)
78+
{
79+
exprt base;
80+
exprt offset;
81+
const integral_resultt &which_side=
82+
get_which_side_integral(expr, base, offset);
83+
INVARIANT(
84+
which_side!=integral_resultt::NEITHER_INTEGRAL,
85+
"An offset must be an integral amount");
86+
87+
if(expr.id()==ID_minus)
88+
{
89+
// can't get a valid pointer by subtracting from a constant number
90+
if(which_side==integral_resultt::LHS_INTEGRAL)
91+
{
92+
top_stack=true;
93+
return;
94+
}
95+
offset.negate();
96+
}
97+
98+
abstract_object_pointert offset_value=environment.eval(offset, ns);
99+
100+
add_to_stack(
101+
std::make_shared<offset_entryt>(offset_value), environment, ns);
102+
103+
// Build the pointer part
104+
construct_stack_to_pointer(base, environment, ns);
105+
106+
if(!top_stack)
107+
{
108+
// check the top of the stack is pointing at an array - we don't support
109+
// offset apart from within arrays
110+
std::shared_ptr<const write_stack_entryt> entry=
111+
*std::prev(stack.cend());
112+
if(entry->get_access_expr().type().id()!=ID_array)
113+
{
114+
top_stack=true;
115+
}
116+
}
117+
}
118+
else
119+
{
120+
// unknown expression type - play it safe and set to top
121+
top_stack=true;
122+
}
123+
}
124+
125+
/// Construct a stack up to a specific l-value (i.e. symbol or position in an
126+
/// array or struct)
127+
/// \param expr: The expression representing a l-value
128+
/// \param environment: The environment to evaluate any expressions in
129+
/// \param ns: The global namespace
130+
void write_stackt::construct_stack_to_lvalue(
131+
const exprt &expr,
132+
const abstract_environmentt &environment,
133+
const namespacet &ns)
134+
{
135+
if(!top_stack)
136+
{
137+
if(expr.id()==ID_member)
138+
{
139+
add_to_stack(std::make_shared<simple_entryt>(expr), environment, ns);
140+
construct_stack_to_lvalue(expr.op0(), environment, ns);
141+
}
142+
else if(expr.id()==ID_symbol)
143+
{
144+
add_to_stack(std::make_shared<simple_entryt>(expr), environment, ns);
145+
}
146+
else if(expr.id()==ID_index)
147+
{
148+
construct_stack_to_array_index(to_index_expr(expr), environment, ns);
149+
}
150+
else
151+
{
152+
top_stack=true;
153+
}
154+
}
155+
}
156+
157+
/// Construct a stack for an array position l-value.
158+
/// \param index_expr: The index expression to construct to.
159+
/// \param environment: The environment to evaluate any expressions in
160+
/// \param ns: The global namespace
161+
void write_stackt::construct_stack_to_array_index(
162+
const index_exprt &index_expr,
163+
const abstract_environmentt &environment,
164+
const namespacet &ns)
165+
{
166+
abstract_object_pointert offset_value=
167+
environment.eval(index_expr.index(), ns);
168+
169+
add_to_stack(std::make_shared<offset_entryt>(offset_value), environment, ns);
170+
construct_stack_to_lvalue(index_expr.array(), environment, ns);
171+
}
172+
173+
/// Convert the stack to an expression that can be used to write to.
174+
/// \return The expression representing the stack, with nil_exprt expressions
175+
/// for top elements.
176+
exprt write_stackt::to_expression() const
177+
{
178+
exprt access_expr=nil_exprt();
179+
for(const std::shared_ptr<write_stack_entryt> &entry : stack)
180+
{
181+
exprt new_expr=entry->get_access_expr();
182+
if(access_expr.id()==ID_nil)
183+
{
184+
access_expr=new_expr;
185+
}
186+
else
187+
{
188+
if(new_expr.operands().size()==0)
189+
{
190+
new_expr.operands().resize(1);
191+
}
192+
new_expr.op0()=access_expr;
193+
194+
access_expr=new_expr;
195+
}
196+
}
197+
address_of_exprt top_expr(access_expr);
198+
return top_expr;
199+
}
200+
201+
/// Is the stack representing an unknown value and hence can't be written to
202+
/// or read from.
203+
/// \return True if the stack is top.
204+
bool write_stackt::is_top_value() const
205+
{
206+
return top_stack;
207+
}
208+
209+
/// Add an element to the top of the stack. This will squash in with the top
210+
/// element if possible.
211+
/// \param entry_pointer: The new element for the stack.
212+
/// \param environment: The environment to evaluate any expressions in
213+
/// \param ns: The global namespace
214+
void write_stackt::add_to_stack(
215+
std::shared_ptr<write_stack_entryt> entry_pointer,
216+
const abstract_environmentt environment,
217+
const namespacet &ns)
218+
{
219+
if(stack.empty() ||
220+
!stack.front()->try_squash_in(entry_pointer, environment, ns))
221+
{
222+
stack.insert(stack.begin(), entry_pointer);
223+
}
224+
}
225+
226+
/// Utility function to find out which side of a binary operation has an
227+
/// integral type, if any.
228+
/// \param expr: The (binary) expression to evaluate.
229+
/// \param [out] out_base_expr: The sub-expression which is not integral typed
230+
/// \param [out] out_integral_expr: The subexpression which is integraled typed.
231+
/// \return: An enum specifying whether the integral type is the LHS (op0),
232+
/// RHS (op1) or neither.
233+
write_stackt::integral_resultt
234+
write_stackt::get_which_side_integral(
235+
const exprt &expr,
236+
exprt &out_base_expr,
237+
exprt &out_integral_expr)
238+
{
239+
PRECONDITION(expr.operands().size()==2);
240+
static const std::unordered_set<irep_idt, irep_id_hash> integral_types=
241+
{ ID_signedbv, ID_unsignedbv, ID_integer };
242+
if(integral_types.find(expr.op0().type().id())!=integral_types.cend())
243+
{
244+
out_integral_expr=expr.op0();
245+
out_base_expr=expr.op1();
246+
return integral_resultt::LHS_INTEGRAL;
247+
}
248+
else if(integral_types.find(expr.op1().type().id())!=integral_types.cend())
249+
{
250+
out_integral_expr=expr.op1();
251+
out_base_expr=expr.op0();
252+
return integral_resultt::RHS_INTEGRAL;
253+
}
254+
else
255+
{
256+
out_integral_expr.make_nil();
257+
out_base_expr.make_nil();
258+
return integral_resultt::NEITHER_INTEGRAL;
259+
}
260+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/*******************************************************************\
2+
3+
Module: Variable Sensitivity Domain
4+
5+
Author: DiffBlue Limited. All rights reserved.
6+
7+
\*******************************************************************/
8+
9+
/// \file
10+
/// Represents a stack of write operations to an addressable memory
11+
/// location
12+
13+
#ifndef CPROVER_ANALYSES_VARIABLE_SENSITIVITY_WRITE_STACK_H
14+
#define CPROVER_ANALYSES_VARIABLE_SENSITIVITY_WRITE_STACK_H
15+
16+
#include <analyses/variable-sensitivity/write_stack_entry.h>
17+
18+
class write_stackt
19+
{
20+
public:
21+
typedef std::vector<std::shared_ptr<write_stack_entryt>>
22+
continuation_stack_storet;
23+
24+
write_stackt();
25+
26+
write_stackt(
27+
const exprt &expr,
28+
const abstract_environmentt &environment,
29+
const namespacet &ns);
30+
31+
exprt to_expression() const;
32+
bool is_top_value() const;
33+
34+
private:
35+
void construct_stack_to_pointer(
36+
const exprt &expr,
37+
const abstract_environmentt &environment,
38+
const namespacet &ns);
39+
40+
void construct_stack_to_lvalue(
41+
const exprt &expr,
42+
const abstract_environmentt &environment,
43+
const namespacet &ns);
44+
45+
void construct_stack_to_array_index(
46+
const index_exprt &expr,
47+
const abstract_environmentt &environment,
48+
const namespacet &ns);
49+
50+
void add_to_stack(
51+
std::shared_ptr<write_stack_entryt> entry_pointer,
52+
const abstract_environmentt environment,
53+
const namespacet &ns);
54+
55+
enum class integral_resultt { LHS_INTEGRAL, RHS_INTEGRAL, NEITHER_INTEGRAL };
56+
57+
static integral_resultt get_which_side_integral(
58+
const exprt &expr,
59+
exprt &out_base_expr,
60+
exprt &out_integral_expr);
61+
62+
continuation_stack_storet stack;
63+
bool top_stack;
64+
};
65+
66+
#endif // CPROVER_ANALYSES_VARIABLE_SENSITIVITY_WRITE_STACK_H

0 commit comments

Comments
 (0)