Skip to content

Commit 352c46b

Browse files
committed
SMT2 backend: lower byte operators before find_symbols
Otherwise the lowering can introduce new array expressions, which the SMT2 backend's convert_expr expects to have been pre-converted into auxiliary symbols.
1 parent 68b192a commit 352c46b

File tree

4 files changed

+120
-31
lines changed

4 files changed

+120
-31
lines changed

regression/cbmc/byte_update10/main.c

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#include <assert.h>
2+
#include <stdio.h>
3+
4+
int main(int argc, char **argv)
5+
{
6+
unsigned long long x[2];
7+
x[0] = 0x0102030405060708;
8+
x[1] = 0x1112131415161718;
9+
10+
unsigned char *alias = (unsigned short *)(((char *)x) + 5);
11+
*alias = 0xed;
12+
13+
unsigned char *alias2 = (unsigned char *)x;
14+
/*
15+
for(int i = 0; i < 16; ++i)
16+
printf("%02hhx\n",alias2[i]);
17+
*/
18+
19+
assert(alias2[0] == 0x08);
20+
assert(alias2[1] == 0x07);
21+
assert(alias2[2] == 0x06);
22+
assert(alias2[3] == 0x05);
23+
assert(alias2[4] == 0x04);
24+
assert(alias2[5] == 0xed);
25+
assert(alias2[6] == 0x02);
26+
assert(alias2[7] == 0x01);
27+
assert(alias2[8] == 0x18);
28+
assert(alias2[9] == 0x17);
29+
assert(alias2[10] == 0x16);
30+
assert(alias2[11] == 0x15);
31+
assert(alias2[12] == 0x14);
32+
assert(alias2[13] == 0x13);
33+
assert(alias2[14] == 0x12);
34+
assert(alias2[15] == 0x11);
35+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
CORE
2+
main.c
3+
--little-endian
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
^warning: ignoring
9+
--
10+
Note this is identical to test byte_update2, except that the array 'x' has
11+
constant size.

src/solvers/smt2/smt2_conv.cpp

Lines changed: 72 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ Author: Daniel Kroening, [email protected]
1414
#include <util/arith_tools.h>
1515
#include <util/c_types.h>
1616
#include <util/config.h>
17+
#include <util/expr_iterator.h>
1718
#include <util/expr_util.h>
1819
#include <util/fixedbv.h>
1920
#include <util/format_expr.h>
@@ -612,24 +613,6 @@ void smt2_convt::convert_address_of_rec(
612613
expr.id_string());
613614
}
614615

615-
void smt2_convt::convert_byte_extract(const byte_extract_exprt &expr)
616-
{
617-
// we just run the flattener
618-
exprt flattened_expr = lower_byte_extract(expr, ns);
619-
unflatten(wheret::BEGIN, expr.type());
620-
convert_expr(flattened_expr);
621-
unflatten(wheret::END, expr.type());
622-
}
623-
624-
void smt2_convt::convert_byte_update(const byte_update_exprt &expr)
625-
{
626-
// we just run the flattener
627-
exprt flattened_expr = lower_byte_update(expr, ns);
628-
unflatten(wheret::BEGIN, expr.type());
629-
convert_expr(flattened_expr);
630-
unflatten(wheret::END, expr.type());
631-
}
632-
633616
literalt smt2_convt::convert(const exprt &expr)
634617
{
635618
PRECONDITION(expr.type().id() == ID_bool);
@@ -647,7 +630,7 @@ literalt smt2_convt::convert(const exprt &expr)
647630

648631
out << "\n";
649632

650-
find_symbols(expr);
633+
exprt prepared_expr = prepare_expr(expr);
651634

652635
literalt l(no_boolean_variables, false);
653636
no_boolean_variables++;
@@ -656,7 +639,7 @@ literalt smt2_convt::convert(const exprt &expr)
656639
out << "(define-fun ";
657640
convert_literal(l);
658641
out << " () Bool ";
659-
convert_expr(expr);
642+
convert_expr(prepared_expr);
660643
out << ")" << "\n";
661644

662645
return l;
@@ -1431,12 +1414,12 @@ void smt2_convt::convert_expr(const exprt &expr)
14311414
else if(expr.id()==ID_byte_extract_little_endian ||
14321415
expr.id()==ID_byte_extract_big_endian)
14331416
{
1434-
convert_byte_extract(to_byte_extract_expr(expr));
1417+
INVARIANT(false, "byte_extract ops should be lowered in prepare_expr");
14351418
}
14361419
else if(expr.id()==ID_byte_update_little_endian ||
14371420
expr.id()==ID_byte_update_big_endian)
14381421
{
1439-
convert_byte_update(to_byte_update_expr(expr));
1422+
INVARIANT(false, "byte_update ops should be lowered in prepare_expr");
14401423
}
14411424
else if(expr.id()==ID_width)
14421425
{
@@ -4058,7 +4041,7 @@ void smt2_convt::set_to(const exprt &expr, bool value)
40584041

40594042
id.type=equal_expr.lhs().type();
40604043
find_symbols(id.type);
4061-
find_symbols(equal_expr.rhs());
4044+
exprt prepared_rhs = prepare_expr(equal_expr.rhs());
40624045

40634046
std::string smt2_identifier=convert_identifier(identifier);
40644047
smt2_identifiers.insert(smt2_identifier);
@@ -4068,38 +4051,98 @@ void smt2_convt::set_to(const exprt &expr, bool value)
40684051

40694052
convert_type(equal_expr.lhs().type());
40704053
out << " ";
4071-
convert_expr(equal_expr.rhs());
4054+
convert_expr(prepared_rhs);
40724055

40734056
out << ")" << "\n";
40744057
return; // done
40754058
}
40764059
}
40774060
}
40784061

4079-
find_symbols(expr);
4062+
exprt prepared_expr = prepare_expr(expr);
40804063

4081-
#if 0
4064+
#if 0
40824065
out << "; CONV: "
40834066
<< format(expr) << "\n";
4084-
#endif
4067+
#endif
40854068

40864069
out << "; set_to " << (value?"true":"false") << "\n"
40874070
<< "(assert ";
40884071

40894072
if(!value)
40904073
{
40914074
out << "(not ";
4092-
convert_expr(expr);
4075+
convert_expr(prepared_expr);
40934076
out << ")";
40944077
}
40954078
else
4096-
convert_expr(expr);
4079+
convert_expr(prepared_expr);
40974080

40984081
out << ")" << "\n"; // assert
40994082

41004083
return;
41014084
}
41024085

4086+
/// Lower byte_update and byte_extract operations within \p expr. Return an
4087+
/// equivalent expression that doesn't use byte operators.
4088+
/// Note this replaces operators post-order (compare \ref lower_byte_operators,
4089+
/// which uses a pre-order walk, replacing in child expressions before the
4090+
/// parent). Pre-order replacement currently fails regression tests: see
4091+
/// https://github.com/diffblue/cbmc/issues/4380
4092+
exprt smt2_convt::lower_byte_operators_rec(const exprt &expr)
4093+
{
4094+
exprt lowered_expr = expr;
4095+
4096+
for(auto it = lowered_expr.depth_begin(), itend = lowered_expr.depth_end();
4097+
it != itend;
4098+
/* No ++it */)
4099+
{
4100+
if(
4101+
it->id() == ID_byte_extract_little_endian ||
4102+
it->id() == ID_byte_extract_big_endian)
4103+
{
4104+
// Note we must recurse to get a fresh iterator because depth_iteratort
4105+
// currently crashes if we try to recurse into an expression we've
4106+
// altered.
4107+
it.mutate() = lower_byte_operators_rec(
4108+
lower_byte_extract(to_byte_extract_expr(*it), ns));
4109+
it.next_sibling_or_parent();
4110+
}
4111+
else if(
4112+
it->id() == ID_byte_update_little_endian ||
4113+
it->id() == ID_byte_update_big_endian)
4114+
{
4115+
// Note we must recurse to get a fresh iterator because depth_iteratort
4116+
// currently crashes if we try to recurse into an expression we've
4117+
// altered.
4118+
it.mutate() = lower_byte_operators_rec(
4119+
lower_byte_update(to_byte_update_expr(*it), ns));
4120+
it.next_sibling_or_parent();
4121+
}
4122+
else
4123+
{
4124+
++it;
4125+
}
4126+
}
4127+
4128+
return lowered_expr;
4129+
}
4130+
4131+
exprt smt2_convt::prepare_expr(const exprt &expr)
4132+
{
4133+
// First, replace byte operators, because they may introduce new array
4134+
// expressions that must be seen by find_symbols:
4135+
exprt lowered_expr = lower_byte_operators_rec(expr);
4136+
INVARIANT(
4137+
!has_byte_operator(lowered_expr),
4138+
"lower_byte_operators_rec should remove all byte operators");
4139+
4140+
// Now create symbols for all composite expressions present in lowered_expr:
4141+
find_symbols(lowered_expr);
4142+
4143+
return lowered_expr;
4144+
}
4145+
41034146
void smt2_convt::find_symbols(const exprt &expr)
41044147
{
41054148
// recursive call on type

src/solvers/smt2/smt2_conv.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,8 +154,6 @@ class smt2_convt:public prop_convt
154154
void flatten_array(const exprt &);
155155

156156
// specific expressions go here
157-
void convert_byte_update(const byte_update_exprt &expr);
158-
void convert_byte_extract(const byte_extract_exprt &expr);
159157
void convert_typecast(const typecast_exprt &expr);
160158
void convert_floatbv_typecast(const floatbv_typecast_exprt &expr);
161159
void convert_struct(const struct_exprt &expr);
@@ -182,6 +180,8 @@ class smt2_convt:public prop_convt
182180
std::string convert_identifier(const irep_idt &identifier);
183181

184182
// auxiliary methods
183+
exprt prepare_expr(const exprt &expr);
184+
exprt lower_byte_operators_rec(const exprt &expr);
185185
void find_symbols(const exprt &expr);
186186
void find_symbols(const typet &type);
187187
void find_symbols_rec(const typet &type, std::set<irep_idt> &recstack);

0 commit comments

Comments
 (0)