Skip to content

Commit c3d954e

Browse files
committed
SMT2 back-end: support empty compound types
Do not construct equalities over expressions the type of which has zero bit width. Also, permit pointer arithmetic over objects of such type (which was previously fixed in 6b09359 for the propositional back-end). Fixes: diffblue#7185
1 parent 53e448b commit c3d954e

File tree

5 files changed

+68
-43
lines changed

5 files changed

+68
-43
lines changed

regression/cbmc/Empty_struct1/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
CORE broken-smt-backend
1+
CORE
22
main.c
33

44
^EXIT=0$

regression/cbmc/empty_compound_type2/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
CORE broken-smt-backend
1+
CORE
22
main.c
33
--pointer-check
44
^EXIT=10$

regression/cbmc/empty_compound_type3/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
CORE broken-smt-backend
1+
CORE
22
main.c
33

44
^EXIT=10$

regression/cbmc/empty_compound_type4/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
CORE broken-smt-backend
1+
CORE
22
main.c
33
--trace
44
^VERIFICATION FAILED$

src/solvers/smt2/smt2_conv.cpp

Lines changed: 64 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -958,6 +958,23 @@ std::string smt2_convt::convert_identifier(const irep_idt &identifier)
958958
return result;
959959
}
960960

961+
/// Returns true iff \p type has effective width of zero bits.
962+
static bool is_zero_width(const typet &type, const namespacet &ns)
963+
{
964+
if(type.id() == ID_empty)
965+
return true;
966+
else if(type.id() == ID_struct_tag)
967+
return is_zero_width(ns.follow_tag(to_struct_tag_type(type)), ns);
968+
else if(type.id() == ID_struct)
969+
return to_struct_type(type).components().empty();
970+
else if(type.id() == ID_union_tag)
971+
return is_zero_width(ns.follow_tag(to_union_tag_type(type)), ns);
972+
else if(type.id() == ID_union)
973+
return to_union_type(type).components().empty();
974+
else
975+
return false;
976+
}
977+
961978
std::string smt2_convt::type2id(const typet &type) const
962979
{
963980
if(type.id()==ID_floatbv)
@@ -1365,11 +1382,18 @@ void smt2_convt::convert_expr(const exprt &expr)
13651382
equal_expr.op0().type() == equal_expr.op1().type(),
13661383
"operands of equal expression shall have same type");
13671384

1368-
out << "(= ";
1369-
convert_expr(equal_expr.op0());
1370-
out << " ";
1371-
convert_expr(equal_expr.op1());
1372-
out << ")";
1385+
if(is_zero_width(equal_expr.lhs().type(), ns))
1386+
{
1387+
convert_expr(true_exprt());
1388+
}
1389+
else
1390+
{
1391+
out << "(= ";
1392+
convert_expr(equal_expr.op0());
1393+
out << " ";
1394+
convert_expr(equal_expr.op1());
1395+
out << ")";
1396+
}
13731397
}
13741398
else if(expr.id() == ID_notequal)
13751399
{
@@ -2369,10 +2393,6 @@ void smt2_convt::convert_expr(const exprt &expr)
23692393
{
23702394
convert_expr(simplify_expr(to_find_first_set_expr(expr).lower(), ns));
23712395
}
2372-
else if(expr.id() == ID_empty_union)
2373-
{
2374-
out << "()";
2375-
}
23762396
else if(expr.id() == ID_bitreverse)
23772397
{
23782398
convert_expr(simplify_expr(to_bitreverse_expr(expr).lower(), ns));
@@ -3597,7 +3617,7 @@ void smt2_convt::convert_plus(const plus_exprt &expr)
35973617
else
35983618
{
35993619
auto element_size_opt = pointer_offset_size(base_type, ns);
3600-
CHECK_RETURN(element_size_opt.has_value() && *element_size_opt >= 1);
3620+
CHECK_RETURN(element_size_opt.has_value() && *element_size_opt >= 0);
36013621
element_size = *element_size_opt;
36023622
}
36033623

@@ -4701,9 +4721,7 @@ void smt2_convt::set_to(const exprt &expr, bool value)
47014721
if(expr.id() == ID_equal && value)
47024722
{
47034723
const equal_exprt &equal_expr=to_equal_expr(expr);
4704-
if(
4705-
equal_expr.lhs().type().id() == ID_empty ||
4706-
equal_expr.rhs().id() == ID_empty_union)
4724+
if(is_zero_width(equal_expr.lhs().type(), ns))
47074725
{
47084726
// ignore equality checking over expressions with empty (void) type
47094727
return;
@@ -4955,21 +4973,24 @@ void smt2_convt::find_symbols(const exprt &expr)
49554973
convert_type(array_type);
49564974
out << ")\n";
49574975

4958-
// use a quantifier-based initialization instead of lambda
4959-
out << "(assert (forall ((i ";
4960-
convert_type(array_type.index_type());
4961-
out << ")) (= (select " << id << " i) ";
4962-
if(array_type.element_type().id() == ID_bool && !use_array_of_bool)
4976+
if(!is_zero_width(array_type.element_type(), ns))
49634977
{
4964-
out << "(ite ";
4965-
convert_expr(array_of.what());
4966-
out << " #b1 #b0)";
4967-
}
4968-
else
4969-
{
4970-
convert_expr(array_of.what());
4978+
// use a quantifier-based initialization instead of lambda
4979+
out << "(assert (forall ((i ";
4980+
convert_type(array_type.index_type());
4981+
out << ")) (= (select " << id << " i) ";
4982+
if(array_type.element_type().id() == ID_bool && !use_array_of_bool)
4983+
{
4984+
out << "(ite ";
4985+
convert_expr(array_of.what());
4986+
out << " #b1 #b0)";
4987+
}
4988+
else
4989+
{
4990+
convert_expr(array_of.what());
4991+
}
4992+
out << ")))\n";
49714993
}
4972-
out << ")))\n";
49734994

49744995
defined_expressions[expr] = id;
49754996
}
@@ -5035,22 +5056,26 @@ void smt2_convt::find_symbols(const exprt &expr)
50355056
convert_type(array_type);
50365057
out << ")" << "\n";
50375058

5038-
for(std::size_t i=0; i<expr.operands().size(); i++)
5059+
if(!is_zero_width(array_type.element_type(), ns))
50395060
{
5040-
out << "(assert (= (select " << id << " ";
5041-
convert_expr(from_integer(i, array_type.index_type()));
5042-
out << ") "; // select
5043-
if(array_type.element_type().id() == ID_bool && !use_array_of_bool)
5044-
{
5045-
out << "(ite ";
5046-
convert_expr(expr.operands()[i]);
5047-
out << " #b1 #b0)";
5048-
}
5049-
else
5061+
for(std::size_t i = 0; i < expr.operands().size(); i++)
50505062
{
5051-
convert_expr(expr.operands()[i]);
5063+
out << "(assert (= (select " << id << " ";
5064+
convert_expr(from_integer(i, array_type.index_type()));
5065+
out << ") "; // select
5066+
if(array_type.element_type().id() == ID_bool && !use_array_of_bool)
5067+
{
5068+
out << "(ite ";
5069+
convert_expr(expr.operands()[i]);
5070+
out << " #b1 #b0)";
5071+
}
5072+
else
5073+
{
5074+
convert_expr(expr.operands()[i]);
5075+
}
5076+
out << "))"
5077+
<< "\n"; // =, assert
50525078
}
5053-
out << "))" << "\n"; // =, assert
50545079
}
50555080

50565081
defined_expressions[expr]=id;

0 commit comments

Comments
 (0)