Skip to content

Commit 6f75660

Browse files
authored
Merge pull request diffblue#47 from diffblue/feature/sensitive-pointers
Sensitive pointers
2 parents e2b6761 + 3824dbd commit 6f75660

16 files changed

+626
-116
lines changed

src/analyses/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ SRC = natural_loops.cpp is_threaded.cpp dirty.cpp interval_analysis.cpp \
1515
variable-sensitivity/pointer_abstract_object.cpp \
1616
variable-sensitivity/struct_abstract_object.cpp \
1717
variable-sensitivity/array_abstract_object.cpp \
18+
variable-sensitivity/constant_pointer_abstract_object.cpp \
1819
# Empty last line
1920

2021
INCLUDES= -I ..

src/analyses/variable-sensitivity/abstract_enviroment.cpp

Lines changed: 143 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <analyses/variable-sensitivity/struct_abstract_object.h>
1515
#include <analyses/variable-sensitivity/pointer_abstract_object.h>
1616
#include <analyses/variable-sensitivity/array_abstract_object.h>
17+
#include <analyses/variable-sensitivity/constant_pointer_abstract_object.h>
1718
#include <analyses/ai.h>
1819
#include <analyses/constant_propagator.h>
1920
#include <util/simplify_expr.h>
@@ -60,7 +61,7 @@ abstract_object_pointert abstract_environmentt::eval(
6061
ID_constant, [&](const exprt &expr)
6162
{
6263
return abstract_object_factory(
63-
expr.type(), to_constant_expr(expr));
64+
expr.type(), to_constant_expr(expr), ns);
6465
}
6566
},
6667
{
@@ -77,12 +78,12 @@ abstract_object_pointert abstract_environmentt::eval(
7778
{
7879
ID_address_of, [&](const exprt &expr)
7980
{
80-
#if 0
81-
address_of_exprt address_expr(to_address_of_expr(expr));
82-
#endif
83-
// TODO(tkiley): This needs special handling
84-
// For now just return top
85-
return abstract_object_factory(expr.type(), true, false);
81+
sharing_ptrt<pointer_abstract_objectt> pointer_object=
82+
std::dynamic_pointer_cast<pointer_abstract_objectt>(
83+
abstract_object_factory(expr.type(), expr, ns));
84+
85+
// Store the abstract object in the pointer
86+
return pointer_object;
8687
}
8788
},
8889
{
@@ -93,7 +94,7 @@ abstract_object_pointert abstract_environmentt::eval(
9394
std::dynamic_pointer_cast<pointer_abstract_objectt>(
9495
eval(dereference.pointer(), ns));
9596

96-
return pointer_abstract_object->read_dereference(*this);
97+
return pointer_abstract_object->read_dereference(*this, ns);
9798
}
9899
},
99100
{
@@ -139,6 +140,7 @@ Function: abstract_environmentt::assign
139140
Inputs:
140141
expr - the expression to assign to
141142
value - the value to assign to the expression
143+
ns - the namespace
142144
143145
Outputs: A boolean, true if the assignment has changed the domain.
144146
@@ -147,11 +149,14 @@ Function: abstract_environmentt::assign
147149
\*******************************************************************/
148150

149151
bool abstract_environmentt::assign(
150-
const exprt &expr, const abstract_object_pointert value)
152+
const exprt &expr, const abstract_object_pointert value, const namespacet &ns)
151153
{
154+
assert(value);
155+
156+
// Build a stack of index, member and dereference accesses which
157+
// we will work through the relevant abstract objects
152158
exprt s = expr;
153159
std::stack<exprt> stactions; // I'm not a continuation, honest guv'
154-
155160
while (s.id() != ID_symbol)
156161
{
157162
if (s.id() == ID_index || s.id() == ID_member || s.id() == ID_dereference)
@@ -169,76 +174,12 @@ bool abstract_environmentt::assign(
169174

170175
symbol_exprt symbol_expr=to_symbol_expr(s);
171176

177+
// This is the root abstract object that is in the map of abstract objects
178+
// It might not have the same type as value if the above stack isn't empty
172179
abstract_object_pointert final_value;
173180

174181
if(!stactions.empty())
175182
{
176-
const exprt & next_expr=stactions.top();
177-
stactions.pop();
178-
179-
typedef std::function<
180-
abstract_object_pointert(
181-
abstract_object_pointert, // The symbol we are modifying
182-
std::stack<exprt>, // The remaining stack
183-
abstract_object_pointert)> // The value we are writing.
184-
stacion_functiont;
185-
186-
// Each handler takes the abstract object referenced, copies it,
187-
// writes according to the type of expression (e.g. for ID_member)
188-
// we would (should!) have an abstract_struct_objectt which has a
189-
// write_member which will attempt to update the abstract object for the
190-
// relevant member. This modified abstract object is returned and this
191-
// is inserted back into the map
192-
std::map<irep_idt,stacion_functiont> handlers=
193-
{
194-
{
195-
ID_index, [&](
196-
const abstract_object_pointert lhs_object,
197-
std::stack<exprt> stack,
198-
abstract_object_pointert rhs_object)
199-
{
200-
sharing_ptrt<array_abstract_objectt> array_abstract_object=
201-
std::dynamic_pointer_cast<array_abstract_objectt>(lhs_object);
202-
sharing_ptrt<array_abstract_objectt> modified_array=
203-
array_abstract_object->write_index(
204-
*this, stactions, to_index_expr(next_expr), rhs_object, false);
205-
return modified_array;
206-
}
207-
},
208-
{
209-
ID_member, [&](
210-
const abstract_object_pointert lhs_object,
211-
std::stack<exprt> stack,
212-
abstract_object_pointert rhs_object)
213-
{
214-
sharing_ptrt<struct_abstract_objectt> struct_abstract_object=
215-
std::dynamic_pointer_cast<struct_abstract_objectt>(lhs_object);
216-
sharing_ptrt<struct_abstract_objectt> modified_struct=
217-
struct_abstract_object->write_component(
218-
*this, stactions, to_member_expr(next_expr), rhs_object);
219-
return modified_struct;
220-
}
221-
},
222-
{
223-
ID_dereference, [&](
224-
const abstract_object_pointert lhs_object,
225-
std::stack<exprt> stack,
226-
abstract_object_pointert rhs_object)
227-
{
228-
sharing_ptrt<pointer_abstract_objectt> pointer_abstract_object=
229-
std::dynamic_pointer_cast<pointer_abstract_objectt>(lhs_object);
230-
sharing_ptrt<pointer_abstract_objectt> modified_pointer=
231-
pointer_abstract_object->write_dereference(
232-
*this, stactions, rhs_object, false);
233-
return modified_pointer;
234-
}
235-
}
236-
};
237-
238-
// We added something to the stack that we couldn't deal with
239-
assert(handlers.find(next_expr.id())!=handlers.end());
240-
assert(value);
241-
242183
// The symbol is not in the map - it is therefore top
243184
abstract_object_pointert symbol_object;
244185
if(map.find(symbol_expr)==map.end())
@@ -249,7 +190,7 @@ bool abstract_environmentt::assign(
249190
{
250191
symbol_object=map[symbol_expr];
251192
}
252-
final_value=handlers[next_expr.id()](symbol_object, stactions, value);
193+
final_value=write(symbol_object, value, stactions, ns, false);
253194
}
254195
else
255196
{
@@ -261,7 +202,6 @@ bool abstract_environmentt::assign(
261202
if (final_value->is_top())
262203
{
263204
map.erase(symbol_expr);
264-
265205
}
266206
else
267207
{
@@ -272,6 +212,120 @@ bool abstract_environmentt::assign(
272212

273213
/*******************************************************************\
274214
215+
Function: abstract_object_pointert abstract_environmentt::write
216+
217+
Inputs:
218+
lhs - the abstract object for the left hand side of the write (i.e. the one
219+
to update).
220+
rhs - the value we are trying to write to the left hand side
221+
remaining_stack - what is left of the stack before the rhs can replace or be
222+
merged with the rhs
223+
ns - the namespace
224+
merge_write - Are re replacing the left hand side with the right hand side
225+
(e.g. we know for a fact that we are overwriting this object)
226+
or could the write in fact not take place and therefore we
227+
should merge to model the case where it did not.
228+
229+
Outputs: A modified version of the rhs after the write has taken place
230+
231+
Purpose: Write an abstract object onto another respecting a stack of
232+
member, index and dereference access. This ping-pongs between
233+
this method and the relevant write methods in abstract_struct,
234+
abstract_pointer and abstract_array until the stack is empty
235+
236+
\*******************************************************************/
237+
238+
abstract_object_pointert abstract_environmentt::write(
239+
abstract_object_pointert lhs,
240+
abstract_object_pointert rhs,
241+
std::stack<exprt> remaining_stack,
242+
const namespacet &ns,
243+
bool merge_write)
244+
{
245+
assert(!remaining_stack.empty());
246+
const exprt & next_expr=remaining_stack.top();
247+
remaining_stack.pop();
248+
249+
typedef std::function<
250+
abstract_object_pointert(
251+
abstract_object_pointert, // The symbol we are modifying
252+
std::stack<exprt>, // The remaining stack
253+
abstract_object_pointert)> // The value we are writing.
254+
stacion_functiont;
255+
256+
// Each handler takes the abstract object referenced, copies it,
257+
// writes according to the type of expression (e.g. for ID_member)
258+
// we would (should!) have an abstract_struct_objectt which has a
259+
// write_member which will attempt to update the abstract object for the
260+
// relevant member. This modified abstract object is returned and this
261+
// is inserted back into the map
262+
std::map<irep_idt, stacion_functiont> handlers=
263+
{
264+
{
265+
ID_index, [&](
266+
const abstract_object_pointert lhs_object,
267+
std::stack<exprt> stack,
268+
abstract_object_pointert rhs_object)
269+
{
270+
sharing_ptrt<array_abstract_objectt> array_abstract_object=
271+
std::dynamic_pointer_cast<array_abstract_objectt>(lhs_object);
272+
273+
sharing_ptrt<array_abstract_objectt> modified_array=
274+
array_abstract_object->write_index(
275+
*this,
276+
stack,
277+
to_index_expr(next_expr),
278+
rhs_object,
279+
merge_write);
280+
281+
return modified_array;
282+
}
283+
},
284+
{
285+
ID_member, [&](
286+
const abstract_object_pointert lhs_object,
287+
std::stack<exprt> stack,
288+
abstract_object_pointert rhs_object)
289+
{
290+
sharing_ptrt<struct_abstract_objectt> struct_abstract_object=
291+
std::dynamic_pointer_cast<struct_abstract_objectt>(lhs_object);
292+
293+
sharing_ptrt<struct_abstract_objectt> modified_struct=
294+
struct_abstract_object->write_component(
295+
*this,
296+
stack,
297+
to_member_expr(next_expr),
298+
rhs_object,
299+
merge_write);
300+
301+
return modified_struct;
302+
}
303+
},
304+
{
305+
ID_dereference, [&](
306+
const abstract_object_pointert lhs_object,
307+
std::stack<exprt> stack,
308+
abstract_object_pointert rhs_object)
309+
{
310+
sharing_ptrt<pointer_abstract_objectt> pointer_abstract_object=
311+
std::dynamic_pointer_cast<pointer_abstract_objectt>(lhs_object);
312+
313+
sharing_ptrt<pointer_abstract_objectt> modified_pointer=
314+
pointer_abstract_object->write_dereference(
315+
*this, ns, stack, rhs_object, merge_write);
316+
317+
return modified_pointer;
318+
}
319+
}
320+
};
321+
322+
// We added something to the stack that we couldn't deal with
323+
assert(handlers.find(next_expr.id())!=handlers.end());
324+
return handlers[next_expr.id()](lhs, remaining_stack, rhs);
325+
}
326+
327+
/*******************************************************************\
328+
275329
Function: abstract_environmentt::assume
276330
277331
Inputs:
@@ -339,6 +393,11 @@ abstract_object_pointert abstract_environmentt::abstract_object_factory(
339393
return abstract_object_pointert(
340394
new constant_abstract_valuet(type, top, bottom));
341395
}
396+
else if(type.id()==ID_pointer)
397+
{
398+
return abstract_object_pointert(
399+
new constant_pointer_abstract_objectt(type, top, bottom, *this));
400+
}
342401
else
343402
{
344403
return abstract_object_pointert(new abstract_objectt(type, top, false));
@@ -361,14 +420,19 @@ Function: abstract_environmentt::abstract_object_factory
361420
\*******************************************************************/
362421

363422
abstract_object_pointert abstract_environmentt::abstract_object_factory(
364-
const typet type, const constant_exprt e) const
423+
const typet type, const exprt e, const namespacet &ns) const
365424
{
366425
assert(type==e.type());
367426
if(type.id()==ID_signedbv || type.id()==ID_bool || type.id()==ID_c_bool)
368427
{
369428
return abstract_object_pointert(
370429
new constant_abstract_valuet(e));
371430
}
431+
else if(type.id()==ID_pointer)
432+
{
433+
return abstract_object_pointert(
434+
new constant_pointer_abstract_objectt(e, *this, ns));
435+
}
372436
else
373437
{
374438
return abstract_object_pointert(new abstract_objectt(e));
@@ -401,7 +465,6 @@ bool abstract_environmentt::merge(const abstract_environmentt &env)
401465

402466
std::stringstream merge_message;
403467

404-
405468
ait<constant_propagator_domaint> ai;
406469
symbol_tablet symbol_table;
407470
namespacet ns(symbol_table);

src/analyses/variable-sensitivity/abstract_enviroment.h

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
#include <map>
1212
#include <memory>
13+
#include <stack>
1314

1415
#include <util/std_expr.h>
1516
#include <util/message.h>
@@ -21,15 +22,25 @@ class abstract_environmentt
2122
// These three are really the heart of the method
2223
virtual abstract_object_pointert eval(
2324
const exprt &expr, const namespacet &ns) const;
24-
virtual bool assign(const exprt &expr, const abstract_object_pointert value);
25+
virtual bool assign(
26+
const exprt &expr,
27+
const abstract_object_pointert value,
28+
const namespacet &ns);
2529
virtual bool assume(const exprt &expr, const namespacet &ns);
2630

31+
virtual abstract_object_pointert write(
32+
abstract_object_pointert lhs,
33+
abstract_object_pointert rhs,
34+
std::stack<exprt> remaining_stack,
35+
const namespacet &ns,
36+
bool merge_write);
37+
2738
virtual abstract_object_pointert abstract_object_factory(
2839
const typet type, bool top=true, bool bottom=false) const;
2940
// For converting constants in the program
3041
// Maybe these two should be compacted to one call...
3142
virtual abstract_object_pointert abstract_object_factory(
32-
const typet type, const constant_exprt e) const;
43+
const typet type, const exprt e, const namespacet &ns) const;
3344

3445

3546
virtual bool merge(const abstract_environmentt &env);
@@ -61,6 +72,8 @@ class abstract_environmentt
6172
// Hook for domain specific handling of operators
6273
virtual abstract_object_pointert eval_rest(const exprt &e) const;
6374

75+
76+
6477
typedef symbol_exprt map_keyt;
6578
std::map<map_keyt, abstract_object_pointert> map;
6679

src/analyses/variable-sensitivity/abstract_object.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ Function: abstract_objectt::abstract_objectt
8787
8888
\*******************************************************************/
8989

90-
abstract_objectt::abstract_objectt(const constant_exprt &expr):
90+
abstract_objectt::abstract_objectt(const exprt &expr):
9191
type(expr.type()), top(true), bottom(false)
9292
{}
9393

@@ -123,8 +123,8 @@ bool abstract_objectt::merge_state(
123123
top=op1->top||op2->top;
124124
bottom=op1->bottom && op2->bottom;
125125

126-
return top!=op1->top || bottom!=op1->bottom;
127126
assert(!(top && bottom));
127+
return top!=op1->top || bottom!=op1->bottom;
128128
}
129129

130130
/*******************************************************************\

0 commit comments

Comments
 (0)