Skip to content

Commit 6685497

Browse files
committed
boolbv_width: distinguish zero from unknown size
Use optionalt to distinguish types of known-zero size from those with unknown size, which previously had the default value of zero. This makes it possible to support index expressions over zero bitwidth arrays without mistaking the situation for an unknown size. (There is not really anything wrong in having empty bitvectors, which we otherwise already support (as of e021eef).)
1 parent 3b340ad commit 6685497

33 files changed

+177
-248
lines changed

Diff for: regression/cbmc/dynamic_sizeof1/test.desc

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
CORE
1+
CORE broken-z3-smt-backend
22
main.c
33

44
^EXIT=0$

Diff for: regression/cbmc/vla1/test.desc

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1-
CORE
1+
CORE broken-cprover-smt-backend
22
main.c
33

44
^EXIT=0$
55
^SIGNAL=0$
66
^VERIFICATION SUCCESSFUL$
77
--
88
^warning: ignoring
9+
--
10+
The SMT back-end does not correctly support structs with non-constant size,
11+
unless named data types are used (as is the case with Z3).

Diff for: src/solvers/flattening/boolbv.cpp

+6-12
Original file line numberDiff line numberDiff line change
@@ -242,22 +242,16 @@ bvt boolbvt::convert_array_comprehension(const array_comprehension_exprt &expr)
242242
{
243243
std::size_t width=boolbv_width(expr.type());
244244

245-
if(width==0)
246-
return conversion_failed(expr);
247-
248245
const exprt &array_size = expr.type().size();
249246

250-
const auto size = numeric_cast<mp_integer>(array_size);
251-
252-
if(!size.has_value())
253-
return conversion_failed(expr);
247+
const auto size = numeric_cast_v<mp_integer>(to_constant_expr(array_size));
254248

255249
typet counter_type = expr.arg().type();
256250

257251
bvt bv;
258252
bv.resize(width);
259253

260-
for(mp_integer i = 0; i < *size; ++i)
254+
for(mp_integer i = 0; i < size; ++i)
261255
{
262256
exprt counter=from_integer(i, counter_type);
263257

@@ -266,7 +260,7 @@ bvt boolbvt::convert_array_comprehension(const array_comprehension_exprt &expr)
266260
const bvt &tmp = convert_bv(body);
267261

268262
INVARIANT(
269-
*size * tmp.size() == width,
263+
size * tmp.size() == width,
270264
"total bitvector width shall equal the number of operands times the size "
271265
"per operand");
272266

@@ -521,12 +515,12 @@ bool boolbvt::is_unbounded_array(const typet &type) const
521515
if(unbounded_array==unbounded_arrayt::U_ALL)
522516
return true;
523517

524-
const std::size_t size = boolbv_width(type);
525-
if(size == 0)
518+
const auto &size_opt = bv_width.get_width_opt(type);
519+
if(!size_opt.has_value())
526520
return true;
527521

528522
if(unbounded_array==unbounded_arrayt::U_AUTO)
529-
if(size > MAX_FLATTENED_ARRAY_SIZE)
523+
if(*size_opt > MAX_FLATTENED_ARRAY_SIZE)
530524
return true;
531525

532526
return false;

Diff for: src/solvers/flattening/boolbv_abs.cpp

-5
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,6 @@ Author: Daniel Kroening, [email protected]
1616

1717
bvt boolbvt::convert_abs(const abs_exprt &expr)
1818
{
19-
const std::size_t width = boolbv_width(expr.type());
20-
21-
if(width==0)
22-
return conversion_failed(expr);
23-
2419
const bvt &op_bv=convert_bv(expr.op());
2520

2621
if(expr.op().type()!=expr.type())

Diff for: src/solvers/flattening/boolbv_add_sub.cpp

-6
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,6 @@ bvt boolbvt::convert_add_sub(const exprt &expr)
3232

3333
std::size_t width=boolbv_width(type);
3434

35-
if(width==0)
36-
return conversion_failed(expr);
37-
3835
const exprt::operandst &operands=expr.operands();
3936

4037
DATA_INVARIANT(
@@ -160,9 +157,6 @@ bvt boolbvt::convert_saturating_add_sub(const binary_exprt &expr)
160157

161158
std::size_t width = boolbv_width(type);
162159

163-
if(width == 0)
164-
return conversion_failed(expr);
165-
166160
DATA_INVARIANT(
167161
expr.lhs().type() == type && expr.rhs().type() == type,
168162
"saturating add/sub with mixed types:\n" + expr.pretty());

Diff for: src/solvers/flattening/boolbv_array_of.cpp

+4-15
Original file line numberDiff line numberDiff line change
@@ -24,28 +24,17 @@ bvt boolbvt::convert_array_of(const array_of_exprt &expr)
2424
return conversion_failed(expr);
2525

2626
std::size_t width=boolbv_width(array_type);
27-
28-
if(width==0)
29-
{
30-
// A zero-length array is acceptable;
31-
// an element with unknown size is not.
32-
if(boolbv_width(array_type.element_type()) == 0)
33-
return conversion_failed(expr);
34-
else
35-
return bvt();
36-
}
27+
if(width == 0)
28+
return bvt{};
3729

3830
const exprt &array_size=array_type.size();
3931

40-
const auto size = numeric_cast<mp_integer>(array_size);
41-
42-
if(!size.has_value())
43-
return conversion_failed(expr);
32+
const auto size = numeric_cast_v<mp_integer>(to_constant_expr(array_size));
4433

4534
const bvt &tmp = convert_bv(expr.what());
4635

4736
INVARIANT(
48-
*size * tmp.size() == width,
37+
size * tmp.size() == width,
4938
"total array bit width shall equal the number of elements times the "
5039
"element bit with");
5140

Diff for: src/solvers/flattening/boolbv_bitreverse.cpp

-2
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@ Author: Michael Tautschnig
1313
bvt boolbvt::convert_bitreverse(const bitreverse_exprt &expr)
1414
{
1515
const std::size_t width = boolbv_width(expr.type());
16-
if(width == 0)
17-
return conversion_failed(expr);
1816

1917
bvt bv = convert_bv(expr.op(), width);
2018

Diff for: src/solvers/flattening/boolbv_bitwise.cpp

-2
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@ Author: Daniel Kroening, [email protected]
1313
bvt boolbvt::convert_bitwise(const exprt &expr)
1414
{
1515
const std::size_t width = boolbv_width(expr.type());
16-
if(width==0)
17-
return conversion_failed(expr);
1816

1917
if(expr.id()==ID_bitnot)
2018
{

Diff for: src/solvers/flattening/boolbv_case.cpp

-3
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,6 @@ bvt boolbvt::convert_case(const exprt &expr)
1818

1919
std::size_t width=boolbv_width(expr.type());
2020

21-
if(width==0)
22-
return conversion_failed(expr);
23-
2421
// make it free variables
2522
bvt bv = prop.new_variables(width);
2623

Diff for: src/solvers/flattening/boolbv_complex.cpp

-9
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,6 @@ bvt boolbvt::convert_complex(const complex_exprt &expr)
1414
{
1515
std::size_t width=boolbv_width(expr.type());
1616

17-
if(width==0)
18-
return conversion_failed(expr);
19-
2017
DATA_INVARIANT(
2118
expr.type().id() == ID_complex,
2219
"complex expression shall have complex type");
@@ -41,9 +38,6 @@ bvt boolbvt::convert_complex_real(const complex_real_exprt &expr)
4138
{
4239
std::size_t width=boolbv_width(expr.type());
4340

44-
if(width==0)
45-
return conversion_failed(expr);
46-
4741
bvt bv = convert_bv(expr.op(), width * 2);
4842

4943
bv.resize(width); // chop
@@ -55,9 +49,6 @@ bvt boolbvt::convert_complex_imag(const complex_imag_exprt &expr)
5549
{
5650
std::size_t width=boolbv_width(expr.type());
5751

58-
if(width==0)
59-
return conversion_failed(expr);
60-
6152
bvt bv = convert_bv(expr.op(), width * 2);
6253

6354
bv.erase(bv.begin(), bv.begin()+width);

Diff for: src/solvers/flattening/boolbv_concatenation.cpp

-3
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,6 @@ bvt boolbvt::convert_concatenation(const concatenation_exprt &expr)
1515
{
1616
std::size_t width=boolbv_width(expr.type());
1717

18-
if(width==0)
19-
return conversion_failed(expr);
20-
2118
const exprt::operandst &operands=expr.operands();
2219

2320
DATA_INVARIANT(

Diff for: src/solvers/flattening/boolbv_cond.cpp

-3
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,6 @@ bvt boolbvt::convert_cond(const cond_exprt &expr)
1616

1717
std::size_t width=boolbv_width(expr.type());
1818

19-
if(width==0)
20-
return conversion_failed(expr);
21-
2219
bvt bv;
2320

2421
DATA_INVARIANT(operands.size() >= 2, "cond must have at least two operands");

Diff for: src/solvers/flattening/boolbv_constant.cpp

-3
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,6 @@ bvt boolbvt::convert_constant(const constant_exprt &expr)
1414
{
1515
std::size_t width=boolbv_width(expr.type());
1616

17-
if(width==0)
18-
return conversion_failed(expr);
19-
2017
bvt bv;
2118
bv.resize(width);
2219

Diff for: src/solvers/flattening/boolbv_div.cpp

-3
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,6 @@ bvt boolbvt::convert_div(const div_exprt &expr)
1919

2020
std::size_t width=boolbv_width(expr.type());
2121

22-
if(width==0)
23-
return conversion_failed(expr);
24-
2522
if(expr.op0().type().id()!=expr.type().id() ||
2623
expr.op1().type().id()!=expr.type().id())
2724
return conversion_failed(expr);

Diff for: src/solvers/flattening/boolbv_extractbits.cpp

-3
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,6 @@ bvt boolbvt::convert_extractbits(const extractbits_exprt &expr)
1515
{
1616
const std::size_t bv_width = boolbv_width(expr.type());
1717

18-
if(bv_width == 0)
19-
return conversion_failed(expr);
20-
2118
auto const &src_bv = convert_bv(expr.src());
2219

2320
auto const maybe_upper_as_int = numeric_cast<mp_integer>(expr.upper());

Diff for: src/solvers/flattening/boolbv_get.cpp

+26-20
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,9 @@ exprt boolbvt::bv_get_rec(
4848
std::size_t offset,
4949
const typet &type) const
5050
{
51-
std::size_t width=boolbv_width(type);
52-
53-
assert(bv.size()>=offset+width);
54-
5551
if(type.id()==ID_bool)
5652
{
53+
PRECONDITION(bv.size() > offset);
5754
// clang-format off
5855
switch(prop.l_get(bv[offset]).get_value())
5956
{
@@ -76,10 +73,14 @@ exprt boolbvt::bv_get_rec(
7673
return bv_get_unbounded_array(expr);
7774

7875
const typet &subtype = array_type.element_type();
79-
std::size_t sub_width=boolbv_width(subtype);
76+
const auto &sub_width_opt = bv_width.get_width_opt(subtype);
8077

81-
if(sub_width!=0)
78+
if(sub_width_opt.has_value() && *sub_width_opt > 0)
8279
{
80+
const std::size_t width = boolbv_width(type);
81+
82+
std::size_t sub_width = *sub_width_opt;
83+
8384
exprt::operandst op;
8485
op.reserve(width/sub_width);
8586

@@ -131,9 +132,7 @@ exprt boolbvt::bv_get_rec(
131132
const member_exprt member{expr, c.get_name(), subtype};
132133
op.push_back(bv_get_rec(member, bv, offset + new_offset, subtype));
133134

134-
std::size_t sub_width = boolbv_width(subtype);
135-
if(sub_width!=0)
136-
new_offset+=sub_width;
135+
new_offset += boolbv_width(subtype);
137136
}
138137

139138
return struct_exprt(std::move(op), type);
@@ -160,9 +159,12 @@ exprt boolbvt::bv_get_rec(
160159
}
161160
else if(type.id()==ID_vector)
162161
{
162+
const std::size_t width = boolbv_width(type);
163+
163164
const auto &vector_type = to_vector_type(type);
164165
const typet &element_type = vector_type.element_type();
165166
std::size_t element_width = boolbv_width(element_type);
167+
CHECK_RETURN(element_width > 0);
166168

167169
if(element_width != 0 && width % element_width == 0)
168170
{
@@ -183,21 +185,25 @@ exprt boolbvt::bv_get_rec(
183185
}
184186
else if(type.id()==ID_complex)
185187
{
186-
const typet &subtype = to_complex_type(type).subtype();
187-
std::size_t sub_width=boolbv_width(subtype);
188+
const std::size_t width = boolbv_width(type);
188189

189-
if(sub_width!=0 && width==sub_width*2)
190-
{
191-
const complex_exprt value(
192-
bv_get_rec(complex_real_exprt{expr}, bv, 0 * sub_width, subtype),
193-
bv_get_rec(complex_imag_exprt{expr}, bv, 1 * sub_width, subtype),
194-
to_complex_type(type));
195-
196-
return value;
197-
}
190+
const typet &subtype = to_complex_type(type).subtype();
191+
const std::size_t sub_width = boolbv_width(subtype);
192+
CHECK_RETURN(sub_width > 0);
193+
DATA_INVARIANT(
194+
width == sub_width * 2,
195+
"complex type has two elements of equal bit width");
196+
197+
return complex_exprt{
198+
bv_get_rec(complex_real_exprt{expr}, bv, 0 * sub_width, subtype),
199+
bv_get_rec(complex_imag_exprt{expr}, bv, 1 * sub_width, subtype),
200+
to_complex_type(type)};
198201
}
199202
}
200203

204+
const std::size_t width = boolbv_width(type);
205+
PRECONDITION(bv.size() >= offset + width);
206+
201207
// most significant bit first
202208
std::string value;
203209

Diff for: src/solvers/flattening/boolbv_index.cpp

+9-13
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,6 @@ bvt boolbvt::convert_index(const index_exprt &expr)
3434
const array_typet &array_type=
3535
to_array_type(array_op_type);
3636

37-
std::size_t width=boolbv_width(expr.type());
38-
39-
if(width==0)
40-
return conversion_failed(expr);
41-
4237
// see if the array size is constant
4338

4439
if(is_unbounded_array(array_type))
@@ -57,9 +52,11 @@ bvt boolbvt::convert_index(const index_exprt &expr)
5752
if(
5853
final_array.id() == ID_symbol || final_array.id() == ID_nondet_symbol)
5954
{
60-
std::size_t width = boolbv_width(array_type);
55+
const auto &array_width_opt = bv_width.get_width_opt(array_type);
6156
(void)map.get_literals(
62-
final_array.get(ID_identifier), array_type, width);
57+
final_array.get(ID_identifier),
58+
array_type,
59+
array_width_opt.value_or(0));
6360
}
6461

6562
// make sure we have the index in the cache
@@ -68,15 +65,16 @@ bvt boolbvt::convert_index(const index_exprt &expr)
6865
else
6966
{
7067
// free variables
71-
bv = prop.new_variables(width);
68+
bv = prop.new_variables(boolbv_width(expr.type()));
7269

7370
record_array_index(expr);
7471

7572
// record type if array is a symbol
7673
if(array.id() == ID_symbol || array.id() == ID_nondet_symbol)
7774
{
78-
std::size_t width = boolbv_width(array_type);
79-
(void)map.get_literals(array.get(ID_identifier), array_type, width);
75+
const auto &array_width_opt = bv_width.get_width_opt(array_type);
76+
(void)map.get_literals(
77+
array.get(ID_identifier), array_type, array_width_opt.value_or(0));
8078
}
8179

8280
// make sure we have the index in the cache
@@ -208,6 +206,7 @@ bvt boolbvt::convert_index(const index_exprt &expr)
208206
// one or more of the above encoding strategies.
209207

210208
// get literals for the whole array
209+
const std::size_t width = boolbv_width(expr.type());
211210

212211
const bvt &array_bv =
213212
convert_bv(array, numeric_cast_v<std::size_t>(array_size * width));
@@ -290,9 +289,6 @@ bvt boolbvt::convert_index(
290289

291290
std::size_t width = boolbv_width(array_type.element_type());
292291

293-
if(width==0)
294-
return conversion_failed(array);
295-
296292
// TODO: If the underlying array can use one of the
297293
// improvements given above then it may be better to use
298294
// the array theory for short chains of updates and then

0 commit comments

Comments
 (0)