Skip to content

Commit 3922701

Browse files
committed
Refactor lvalue-retainment in replace_symbolt into a separate class
1 parent aef0d05 commit 3922701

File tree

6 files changed

+183
-40
lines changed

6 files changed

+183
-40
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#include <assert.h>
2+
3+
int main()
4+
{
5+
int i = 0;
6+
int *p = &i;
7+
assert(*p == 0);
8+
return 0;
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
main.c
3+
--constant-propagator
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
VERIFICATION SUCCESSFUL
7+
--
8+
^warning: ignoring

src/analyses/constant_propagator.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ class constant_propagator_domaint:public ai_domain_baset
7171
struct valuest
7272
{
7373
// maps variables to constants
74-
replace_symbolt replace_const;
74+
address_of_aware_replace_symbolt replace_const;
7575
bool is_bottom = true;
7676

7777
bool merge(const valuest &src);

src/util/replace_symbol.cpp

+99-21
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,19 @@ void replace_symbolt::insert(
2727
old_expr.get_identifier(), new_expr));
2828
}
2929

30-
bool replace_symbolt::replace(
31-
exprt &dest,
32-
const bool replace_with_const) const
30+
bool replace_symbolt::replace_symbol_expr(symbol_exprt &s) const
31+
{
32+
expr_mapt::const_iterator it = expr_map.find(s.get_identifier());
33+
34+
if(it == expr_map.end())
35+
return true;
36+
37+
static_cast<exprt &>(s) = it->second;
38+
39+
return false;
40+
}
41+
42+
bool replace_symbolt::replace(exprt &dest) const
3343
{
3444
bool result=true; // unchanged
3545

@@ -49,14 +59,14 @@ bool replace_symbolt::replace(
4959
{
5060
member_exprt &me=to_member_expr(dest);
5161

52-
if(!replace(me.struct_op(), replace_with_const)) // Could give non l-value.
62+
if(!replace(me.struct_op()))
5363
result=false;
5464
}
5565
else if(dest.id()==ID_index)
5666
{
5767
index_exprt &ie=to_index_expr(dest);
5868

59-
if(!replace(ie.array(), replace_with_const)) // Could give non l-value.
69+
if(!replace(ie.array()))
6070
result=false;
6171

6272
if(!replace(ie.index()))
@@ -66,27 +76,13 @@ bool replace_symbolt::replace(
6676
{
6777
address_of_exprt &aoe=to_address_of_expr(dest);
6878

69-
if(!replace(aoe.object(), false))
79+
if(!replace(aoe.object()))
7080
result=false;
7181
}
7282
else if(dest.id()==ID_symbol)
7383
{
74-
const symbol_exprt &s=to_symbol_expr(dest);
75-
76-
expr_mapt::const_iterator it=
77-
expr_map.find(s.get_identifier());
78-
79-
if(it!=expr_map.end())
80-
{
81-
const exprt &e=it->second;
82-
83-
if(!replace_with_const && e.is_constant()) // Would give non l-value.
84-
return true;
85-
86-
dest=e;
87-
84+
if(!replace_symbol_expr(to_symbol_expr(dest)))
8885
return false;
89-
}
9086
}
9187
else
9288
{
@@ -252,3 +248,85 @@ void unchecked_replace_symbolt::insert(
252248
{
253249
expr_map.emplace(old_expr.get_identifier(), new_expr);
254250
}
251+
252+
bool address_of_aware_replace_symbolt::replace(exprt &dest) const
253+
{
254+
const exprt &const_dest(dest);
255+
if(!require_lvalue && const_dest.id() != ID_address_of)
256+
return unchecked_replace_symbolt::replace(dest);
257+
258+
bool result=true; // unchanged
259+
260+
// first look at type
261+
if(have_to_replace(const_dest.type()))
262+
{
263+
const set_require_lvalue_and_backupt backup(require_lvalue, false);
264+
if(!unchecked_replace_symbolt::replace(dest.type()))
265+
result=false;
266+
}
267+
268+
// now do expression itself
269+
270+
if(!have_to_replace(dest))
271+
return result;
272+
273+
if(dest.id()==ID_index)
274+
{
275+
index_exprt &ie=to_index_expr(dest);
276+
277+
// Could yield non l-value.
278+
if(!replace(ie.array()))
279+
result=false;
280+
281+
const set_require_lvalue_and_backupt backup(require_lvalue, false);
282+
if(!replace(ie.index()))
283+
result=false;
284+
}
285+
else if(dest.id()==ID_address_of)
286+
{
287+
address_of_exprt &aoe=to_address_of_expr(dest);
288+
289+
const set_require_lvalue_and_backupt backup(require_lvalue, true);
290+
if(!replace(aoe.object()))
291+
result=false;
292+
}
293+
else
294+
{
295+
if(!unchecked_replace_symbolt::replace(dest))
296+
return false;
297+
}
298+
299+
const set_require_lvalue_and_backupt backup(require_lvalue, false);
300+
301+
const typet &c_sizeof_type =
302+
static_cast<const typet&>(dest.find(ID_C_c_sizeof_type));
303+
if(c_sizeof_type.is_not_nil() && have_to_replace(c_sizeof_type))
304+
result &= unchecked_replace_symbolt::replace(
305+
static_cast<typet&>(dest.add(ID_C_c_sizeof_type)));
306+
307+
const typet &va_arg_type =
308+
static_cast<const typet&>(dest.find(ID_C_va_arg_type));
309+
if(va_arg_type.is_not_nil() && have_to_replace(va_arg_type))
310+
result &= unchecked_replace_symbolt::replace(
311+
static_cast<typet&>(dest.add(ID_C_va_arg_type)));
312+
313+
return result;
314+
}
315+
316+
bool address_of_aware_replace_symbolt::replace_symbol_expr(
317+
symbol_exprt &s) const
318+
{
319+
expr_mapt::const_iterator it = expr_map.find(s.get_identifier());
320+
321+
if(it == expr_map.end())
322+
return true;
323+
324+
const exprt &e = it->second;
325+
326+
if(require_lvalue && e.is_constant()) // Would give non l-value.
327+
return true;
328+
329+
static_cast<exprt &>(s) = e;
330+
331+
return false;
332+
}

src/util/replace_symbol.h

+41-17
Original file line numberDiff line numberDiff line change
@@ -28,22 +28,7 @@ class replace_symbolt
2828
void insert(const class symbol_exprt &old_expr,
2929
const exprt &new_expr);
3030

31-
/// \brief Replaces a symbol with a constant
32-
/// If you are replacing symbols with constants in an l-value, you can
33-
/// create something that is not an l-value. For example if your
34-
/// l-value is "a[i]" then substituting i for a constant results in an
35-
/// l-value but substituting a for a constant (array) wouldn't. This
36-
/// only applies to the "top level" of the expression, for example, it
37-
/// is OK to replace b with a constant array in a[b[0]].
38-
///
39-
/// \param dest The expression in which to do the replacement
40-
/// \param replace_with_const If false then it disables the rewrites that
41-
/// could result in something that is not an l-value.
42-
///
43-
virtual bool replace(
44-
exprt &dest,
45-
const bool replace_with_const=true) const;
46-
31+
virtual bool replace(exprt &dest) const;
4732
virtual bool replace(typet &dest) const;
4833

4934
void operator()(exprt &dest) const
@@ -92,7 +77,8 @@ class replace_symbolt
9277
protected:
9378
expr_mapt expr_map;
9479

95-
protected:
80+
virtual bool replace_symbol_expr(symbol_exprt &dest) const;
81+
9682
bool have_to_replace(const exprt &dest) const;
9783
bool have_to_replace(const typet &type) const;
9884
};
@@ -107,4 +93,42 @@ class unchecked_replace_symbolt : public replace_symbolt
10793
void insert(const symbol_exprt &old_expr, const exprt &new_expr);
10894
};
10995

96+
/// Replace symbols with constants while maintaining syntactically valid
97+
/// expressions.
98+
/// If you are replacing symbols with constants in an l-value, you can
99+
/// create something that is not an l-value. For example if your
100+
/// l-value is "a[i]" then substituting i for a constant results in an
101+
/// l-value but substituting a for a constant (array) wouldn't. This
102+
/// only applies to the "top level" of the expression, for example, it
103+
/// is OK to replace b with a constant array in a[b[0]].
104+
class address_of_aware_replace_symbolt : public unchecked_replace_symbolt
105+
{
106+
public:
107+
bool replace(exprt &dest) const override;
108+
109+
private:
110+
mutable bool require_lvalue = false;
111+
112+
class set_require_lvalue_and_backupt
113+
{
114+
public:
115+
set_require_lvalue_and_backupt(bool &require_lvalue, const bool value)
116+
: require_lvalue(require_lvalue), prev_value(require_lvalue)
117+
{
118+
require_lvalue = value;
119+
}
120+
121+
~set_require_lvalue_and_backupt()
122+
{
123+
require_lvalue = prev_value;
124+
}
125+
126+
private:
127+
bool &require_lvalue;
128+
bool prev_value;
129+
};
130+
131+
bool replace_symbol_expr(symbol_exprt &dest) const override;
132+
};
133+
110134
#endif // CPROVER_UTIL_REPLACE_SYMBOL_H

unit/util/replace_symbol.cpp

+25-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ TEST_CASE("Lvalue only", "[core][util][replace_symbol]")
6262

6363
constant_exprt c("some_value", typet("some_type"));
6464

65-
replace_symbolt r;
65+
address_of_aware_replace_symbolt r;
6666
r.insert(s1, c);
6767

6868
REQUIRE(r.replace(binary) == false);
@@ -72,3 +72,27 @@ TEST_CASE("Lvalue only", "[core][util][replace_symbol]")
7272
REQUIRE(to_array_type(index_expr.array().type()).size() == c);
7373
REQUIRE(index_expr.index() == c);
7474
}
75+
76+
TEST_CASE("Replace always", "[core][util][replace_symbol]")
77+
{
78+
symbol_exprt s1("a", typet("some_type"));
79+
array_typet array_type(typet("some_type"), s1);
80+
symbol_exprt array("b", array_type);
81+
index_exprt index(array, s1);
82+
83+
exprt binary("binary", typet("some_type"));
84+
binary.copy_to_operands(address_of_exprt(s1));
85+
binary.copy_to_operands(address_of_exprt(index));
86+
87+
constant_exprt c("some_value", typet("some_type"));
88+
89+
unchecked_replace_symbolt r;
90+
r.insert(s1, c);
91+
92+
REQUIRE(r.replace(binary) == false);
93+
REQUIRE(binary.op0() == address_of_exprt(c));
94+
const index_exprt &index_expr =
95+
to_index_expr(to_address_of_expr(binary.op1()).object());
96+
REQUIRE(to_array_type(index_expr.array().type()).size() == c);
97+
REQUIRE(index_expr.index() == c);
98+
}

0 commit comments

Comments
 (0)