Skip to content

Commit 97fbe27

Browse files
committed
Use byte-operator lowering when type to be extract is of non-const size
The test included made apparent that we weren't yet handling unbounded byte extracts (out of a bounded object) in flattening.
1 parent b4a4122 commit 97fbe27

File tree

8 files changed

+86
-18
lines changed

8 files changed

+86
-18
lines changed

regression/cbmc/union17/main.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
int main()
2+
{
3+
// create a union type of non-constant, non-zero size
4+
unsigned x;
5+
__CPROVER_assume(x > 0);
6+
union U
7+
{
8+
unsigned A[x];
9+
};
10+
// create an integer of arbitrary value
11+
int i, i_before;
12+
i_before = i;
13+
// initialize a union of non-zero size from the integer
14+
unsigned u = ((union U *)&i)->A[0];
15+
// reading back an integer out of the union should yield the same value for
16+
// the integer as it had before
17+
i = u;
18+
__CPROVER_assert(i == i_before, "going through union works");
19+
}

regression/cbmc/union17/test.desc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
KNOWNBUG
2+
main.c
3+
--no-simplify
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
^warning: ignoring
9+
--
10+
This test passes when simplification is enabled (which gets rid of
11+
byte-extracting a union of non-constant size), but yields the wrong verification
12+
outcome with both the SAT and SMT back-end otherwise.

src/solvers/flattening/boolbv.cpp

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,23 +8,25 @@ Author: Daniel Kroening, [email protected]
88

99
#include "boolbv.h"
1010

11-
#include <algorithm>
12-
1311
#include <util/arith_tools.h>
1412
#include <util/bitvector_expr.h>
1513
#include <util/bitvector_types.h>
1614
#include <util/byte_operators.h>
15+
#include <util/c_types.h>
1716
#include <util/config.h>
1817
#include <util/floatbv_expr.h>
1918
#include <util/magic.h>
2019
#include <util/mp_arith.h>
20+
#include <util/namespace.h>
2121
#include <util/simplify_expr.h>
2222
#include <util/std_expr.h>
2323
#include <util/string2int.h>
2424
#include <util/string_constant.h>
2525

2626
#include <solvers/floatbv/float_utils.h>
2727

28+
#include <algorithm>
29+
2830
endianness_mapt boolbvt::endianness_map(const typet &type) const
2931
{
3032
const bool little_endian =
@@ -534,6 +536,38 @@ bool boolbvt::is_unbounded_array(const typet &type) const
534536
return false;
535537
}
536538

539+
bool boolbvt::has_unbounded_array(const typet &type) const
540+
{
541+
if(type.id() == ID_struct_tag)
542+
return has_unbounded_array(ns.follow_tag(to_struct_tag_type(type)));
543+
else if(type.id() == ID_union_tag)
544+
return has_unbounded_array(ns.follow_tag(to_union_tag_type(type)));
545+
else if(type.id() == ID_struct)
546+
{
547+
for(const auto &component : to_struct_type(type).components())
548+
{
549+
if(has_unbounded_array(component.type()))
550+
return true;
551+
}
552+
553+
return false;
554+
}
555+
else if(type.id() == ID_union)
556+
{
557+
for(const auto &component : to_union_type(type).components())
558+
{
559+
if(has_unbounded_array(component.type()))
560+
return true;
561+
}
562+
563+
return false;
564+
}
565+
else if(type.id() != ID_array)
566+
return false;
567+
568+
return is_unbounded_array(type);
569+
}
570+
537571
binding_exprt::variablest boolbvt::fresh_binding(const binding_exprt &binding)
538572
{
539573
// to ensure freshness of the new identifiers

src/solvers/flattening/boolbv.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,7 @@ class boolbvt:public arrayst
251251

252252
// unbounded arrays
253253
bool is_unbounded_array(const typet &type) const override;
254+
bool has_unbounded_array(const typet &type) const;
254255

255256
// quantifier instantiations
256257
class quantifiert

src/solvers/flattening/boolbv_array.cpp

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,18 @@ Author: Daniel Kroening, [email protected]
1515
/// Return an empty vector if the width is zero or the array has no elements.
1616
bvt boolbvt::convert_array(const exprt &expr)
1717
{
18-
const std::size_t width = boolbv_width(expr.type());
1918
const exprt::operandst &operands = expr.operands();
2019

21-
if(operands.empty() && width == 0)
20+
if(operands.empty())
2221
return bvt();
2322

2423
if(expr.type().id()==ID_array)
2524
{
26-
DATA_INVARIANT(
27-
expr.has_operands(),
28-
"the bit width being nonzero implies that the array has a nonzero size "
29-
"in which case the array shall have operands");
30-
const std::size_t op_width = width / operands.size();
25+
const std::size_t op_width =
26+
boolbv_width(to_array_type(expr.type()).element_type());
3127

3228
bvt bv;
33-
bv.reserve(width);
29+
bv.reserve(op_width * operands.size());
3430

3531
for(const auto &op : operands)
3632
{

src/solvers/flattening/boolbv_byte_extract.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,18 @@ bvt map_bv(const endianness_mapt &map, const bvt &src)
3434

3535
bvt boolbvt::convert_byte_extract(const byte_extract_exprt &expr)
3636
{
37+
const auto &width_opt = bv_width.get_width_opt(expr.type());
38+
3739
// array logic does not handle byte operators, thus lower when operating on
3840
// unbounded arrays
39-
if(is_unbounded_array(expr.op().type()))
41+
if(
42+
has_unbounded_array(expr.op().type()) || has_unbounded_array(expr.type()) ||
43+
!width_opt.has_value())
4044
{
4145
return convert_bv(lower_byte_extract(expr, ns));
4246
}
4347

44-
const std::size_t width = boolbv_width(expr.type());
48+
const std::size_t width = *width_opt;
4549

4650
// special treatment for bit-fields and big-endian:
4751
// we need byte granularity

src/solvers/flattening/boolbv_byte_update.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ bvt boolbvt::convert_byte_update(const byte_update_exprt &expr)
1919
// if we update (from) an unbounded array, lower the expression as the array
2020
// logic does not handle byte operators
2121
if(
22-
is_unbounded_array(expr.op().type()) ||
23-
is_unbounded_array(expr.value().type()))
22+
has_unbounded_array(expr.op().type()) ||
23+
has_unbounded_array(expr.value().type()))
2424
{
2525
return convert_bv(lower_byte_update(expr, ns));
2626
}

src/solvers/flattening/boolbv_union.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,19 @@ Author: Daniel Kroening, [email protected]
1010

1111
bvt boolbvt::convert_union(const union_exprt &expr)
1212
{
13-
std::size_t width=boolbv_width(expr.type());
14-
1513
const bvt &op_bv=convert_bv(expr.op());
1614

15+
const auto &width_opt = bv_width.get_width_opt(expr.type());
16+
if(!width_opt.has_value())
17+
return op_bv;
18+
1719
INVARIANT(
18-
op_bv.size() <= width,
20+
op_bv.size() <= *width_opt,
1921
"operand bitvector width shall not be larger than the width indicated by "
2022
"the union type");
2123

2224
bvt bv;
23-
bv.resize(width);
25+
bv.resize(*width_opt);
2426

2527
endianness_mapt map_u = endianness_map(expr.type());
2628
endianness_mapt map_op = endianness_map(expr.op().type());

0 commit comments

Comments
 (0)