Skip to content

Commit 6f82023

Browse files
authored
Merge pull request #7669 from tautschnig/bugfixes/7654-byte-extract
Byte-extract lowering: do not blindly use offsets
2 parents 5cd2d1b + d4e61f8 commit 6f82023

File tree

5 files changed

+86
-47
lines changed

5 files changed

+86
-47
lines changed

regression/cbmc/byte_extract2/main.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#include <assert.h>
2+
3+
#define SIZE 1
4+
5+
struct s
6+
{
7+
char a1[1];
8+
unsigned int a2_len;
9+
char a2[SIZE];
10+
};
11+
12+
void main()
13+
{
14+
struct s s1;
15+
char buf[SIZE];
16+
17+
__CPROVER_assume(s1.a2_len <= SIZE);
18+
__CPROVER_assume(s1.a2_len >= SIZE);
19+
char src_n[s1.a2_len];
20+
__CPROVER_array_copy(src_n, s1.a2);
21+
assert(src_n[0] == s1.a2[0]);
22+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
CORE broken-cprover-smt-backend
2+
main.c
3+
4+
^VERIFICATION SUCCESSFUL$
5+
^EXIT=0$
6+
^SIGNAL=0$
7+
--
8+
^warning: ignoring
9+
--
10+
The CPROVER SMT2 back-end does not support quantifiers, which are brought into
11+
this example via an array comprehension.

src/solvers/smt2/smt2_conv.cpp

Lines changed: 18 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3280,49 +3280,37 @@ void smt2_convt::convert_struct(const struct_exprt &expr)
32803280
}
32813281
else
32823282
{
3283-
if(components.size()==1)
3284-
{
3285-
const exprt &op = expr.op0();
3283+
auto convert_operand = [this](const exprt &op) {
32863284
// may need to flatten array-theory arrays in there
32873285
if(op.type().id() == ID_array && use_array_theory(op))
32883286
flatten_array(op);
32893287
else if(op.type().id() == ID_bool)
32903288
flatten2bv(op);
32913289
else
32923290
convert_expr(op);
3293-
}
3294-
else
3291+
};
3292+
3293+
// SMT-LIB 2 concat is binary only
3294+
std::size_t n_concat = 0;
3295+
for(std::size_t i = components.size(); i > 1; i--)
32953296
{
3296-
// SMT-LIB 2 concat is binary only
3297-
std::size_t n_concat = 0;
3298-
for(std::size_t i=components.size(); i>1; i--)
3297+
if(is_zero_width(components[i - 1].type(), ns))
3298+
continue;
3299+
else if(i > 2 || !is_zero_width(components[0].type(), ns))
32993300
{
3300-
if(is_zero_width(components[i - 1].type(), ns))
3301-
continue;
3302-
else if(i > 2 || !is_zero_width(components[0].type(), ns))
3303-
{
3304-
++n_concat;
3305-
out << "(concat ";
3306-
}
3307-
3308-
exprt op=expr.operands()[i-1];
3309-
3310-
// may need to flatten array-theory arrays in there
3311-
if(op.type().id() == ID_array && use_array_theory(op))
3312-
flatten_array(op);
3313-
else if(op.type().id() == ID_bool)
3314-
flatten2bv(op);
3315-
else
3316-
convert_expr(op);
3317-
3318-
out << " ";
3301+
++n_concat;
3302+
out << "(concat ";
33193303
}
33203304

3321-
if(!is_zero_width(components[0].type(), ns))
3322-
convert_expr(expr.op0());
3305+
convert_operand(expr.operands()[i - 1]);
33233306

3324-
out << std::string(n_concat, ')');
3307+
out << " ";
33253308
}
3309+
3310+
if(!is_zero_width(components[0].type(), ns))
3311+
convert_operand(expr.op0());
3312+
3313+
out << std::string(n_concat, ')');
33263314
}
33273315
}
33283316

src/solvers/smt2/smt2_parser.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1207,7 +1207,7 @@ void smt2_parsert::setup_expressions()
12071207

12081208
// add the widths
12091209
auto op_width = make_range(op).map(
1210-
[](const exprt &o) { return to_unsignedbv_type(o.type()).get_width(); });
1210+
[](const exprt &o) { return to_bitvector_type(o.type()).get_width(); });
12111211

12121212
const std::size_t total_width =
12131213
std::accumulate(op_width.begin(), op_width.end(), 0);

src/util/lower_byte_operators.cpp

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -522,9 +522,10 @@ static exprt unpack_array_vector_no_known_bounds(
522522

523523
/// Rewrite an array or vector into its individual bytes.
524524
/// \param src: array/vector to unpack
525-
/// \param src_size: array/vector size; if not a constant and thus not set,
526-
/// \p max_bytes must be a known constant value to build an array expression,
527-
/// otherwise we fall back to building and array comprehension
525+
/// \param src_size: number of elements in \p src, if the array/vector size is
526+
/// constant; if the array/vector size is not constant (and this argument thus
527+
/// not set), \p max_bytes needs to be a known constant value to build an
528+
/// array expression, else we fall back to building an array comprehension
528529
/// \param element_bits: bit width of array/vector elements
529530
/// \param little_endian: true, iff assumed endianness is little-endian
530531
/// \param offset_bytes: if set, bytes prior to this offset will be filled
@@ -576,7 +577,9 @@ static exprt unpack_array_vector(
576577
first_element = *offset_bytes / el_bytes;
577578
// insert offset_bytes-many nil bytes into the output array
578579
byte_operands.resize(
579-
numeric_cast_v<std::size_t>(*offset_bytes - (*offset_bytes % el_bytes)),
580+
numeric_cast_v<std::size_t>(std::min(
581+
*offset_bytes - (*offset_bytes % el_bytes),
582+
*num_elements * el_bytes)),
580583
from_integer(0, bv_typet{bits_per_byte}));
581584
}
582585
}
@@ -777,24 +780,39 @@ static array_exprt unpack_struct(
777780
!bit_fields.has_value(),
778781
"all preceding members should have been processed");
779782

780-
exprt sub = unpack_rec(
781-
member,
782-
little_endian,
783-
offset_in_member,
784-
max_bytes_left,
785-
bits_per_byte,
786-
ns,
787-
true);
783+
if(
784+
component_bits.has_value() && offset_in_member.has_value() &&
785+
*offset_in_member * bits_per_byte >= *component_bits)
786+
{
787+
// we won't actually need this component, fill in zeros instead of
788+
// computing an unpacking
789+
byte_operands.resize(
790+
byte_operands.size() +
791+
numeric_cast_v<std::size_t>(*component_bits / bits_per_byte),
792+
from_integer(0, bv_typet{bits_per_byte}));
793+
}
794+
else
795+
{
796+
exprt sub = unpack_rec(
797+
member,
798+
little_endian,
799+
offset_in_member,
800+
max_bytes_left,
801+
bits_per_byte,
802+
ns,
803+
true);
788804

789-
byte_operands.insert(
790-
byte_operands.end(),
791-
std::make_move_iterator(sub.operands().begin()),
792-
std::make_move_iterator(sub.operands().end()));
805+
byte_operands.insert(
806+
byte_operands.end(),
807+
std::make_move_iterator(sub.operands().begin()),
808+
std::make_move_iterator(sub.operands().end()));
809+
}
793810

794811
if(component_bits.has_value())
795812
member_offset_bits += *component_bits;
796813
}
797814

815+
// any remaining bit fields?
798816
if(bit_fields.has_value())
799817
{
800818
process_bit_fields(

0 commit comments

Comments
 (0)