Skip to content

Commit c9e923d

Browse files
committed
Byte update lowering: never create extractbits over unbounded arrays
With nondet pointers we may end up doing byte updates of weird combinations, including doing byte updates of an unbounded array using a value the size of which is not a multiple of byte widths. This resulted in extractbits expressions trying to extract bits from an unbounded array, which bitvector flattening does not support. This commit puts a byte extract layer in between, which will then take the right approach to ultimately enable the extractbits to succeed. Also, put PRECONDITIONs in place to ensure we don't create such extractbits expressions in any other place in byte-operator lowering.
1 parent a0d4239 commit c9e923d

File tree

4 files changed

+54
-10
lines changed

4 files changed

+54
-10
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
main.c
3+
--big-endian
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
^warning: ignoring
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
main.c
3+
--little-endian
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
^warning: ignoring

regression/cbmc/byte_update16/main.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
int main()
2+
{
3+
unsigned len;
4+
unsigned A[len];
5+
if(len > 1 || len == 0 || sizeof(unsigned) != 4)
6+
return 0;
7+
8+
A[0] = 0xA5FFFFA5U;
9+
__CPROVER_bitvector[1] *bptr = &A[len - 1];
10+
*bptr = 0;
11+
__CPROVER_assert(A[0] == 0xA5FFFF25U || A[0] == 0x25FFFFA5U, "MSB cleared");
12+
}

src/solvers/lowering/byte_operators.cpp

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ static struct_exprt bv_to_struct_expr(
108108
member_offset_bits,
109109
member_offset_bits + component_bits - 1);
110110
bitvector_typet type = adjust_width(bitvector_expr.type(), component_bits);
111+
PRECONDITION(pointer_offset_bits(bitvector_expr.type(), ns).has_value());
111112
operands.push_back(bv_to_expr(
112113
extractbits_exprt{bitvector_expr, bounds.ub, bounds.lb, std::move(type)},
113114
comp.type(),
@@ -158,6 +159,7 @@ static union_exprt bv_to_union_expr(
158159
const typet &component_type = widest_member.has_value()
159160
? widest_member->first.type()
160161
: components.front().type();
162+
PRECONDITION(pointer_offset_bits(bitvector_expr.type(), ns).has_value());
161163
return union_exprt{
162164
component_name,
163165
bv_to_expr(
@@ -205,6 +207,7 @@ static array_exprt bv_to_array_expr(
205207
endianness_map, i * subtype_bits_int, ((i + 1) * subtype_bits_int) - 1);
206208
bitvector_typet type =
207209
adjust_width(bitvector_expr.type(), subtype_bits_int);
210+
PRECONDITION(pointer_offset_bits(bitvector_expr.type(), ns).has_value());
208211
operands.push_back(bv_to_expr(
209212
extractbits_exprt{
210213
bitvector_expr, bounds.ub, bounds.lb, std::move(type)},
@@ -251,6 +254,7 @@ static vector_exprt bv_to_vector_expr(
251254
endianness_map, i * subtype_bits_int, ((i + 1) * subtype_bits_int) - 1);
252255
bitvector_typet type =
253256
adjust_width(bitvector_expr.type(), subtype_bits_int);
257+
PRECONDITION(pointer_offset_bits(bitvector_expr.type(), ns).has_value());
254258
operands.push_back(bv_to_expr(
255259
extractbits_exprt{
256260
bitvector_expr, bounds.ub, bounds.lb, std::move(type)},
@@ -297,6 +301,7 @@ static complex_exprt bv_to_complex_expr(
297301
const bitvector_typet type =
298302
adjust_width(bitvector_expr.type(), subtype_bits);
299303

304+
PRECONDITION(pointer_offset_bits(bitvector_expr.type(), ns).has_value());
300305
return complex_exprt{
301306
bv_to_expr(
302307
extractbits_exprt{bitvector_expr, bounds_real.ub, bounds_real.lb, type},
@@ -946,6 +951,8 @@ static exprt unpack_rec(
946951
exprt::operandst byte_operands;
947952
for(; bit_offset < last_bit; bit_offset += 8)
948953
{
954+
PRECONDITION(
955+
pointer_offset_bits(src_as_bitvector.type(), ns).has_value());
949956
extractbits_exprt extractbits(
950957
src_as_bitvector,
951958
from_integer(bit_offset + 7, c_index_type()),
@@ -2013,6 +2020,7 @@ static exprt lower_byte_update_struct(
20132020
elements.push_back(updated_element);
20142021
else
20152022
{
2023+
PRECONDITION(pointer_offset_bits(updated_element.type(), ns).has_value());
20162024
elements.push_back(typecast_exprt::conditional_cast(
20172025
extractbits_exprt{updated_element,
20182026
element_bits_int - 1 + (little_endian ? shift : 0),
@@ -2255,6 +2263,7 @@ static exprt lower_byte_update(
22552263
bitor_expr.type(), src.id() == ID_byte_update_little_endian, ns);
22562264
const auto bounds = map_bounds(endianness_map, 0, type_bits - 1);
22572265

2266+
PRECONDITION(pointer_offset_bits(bitor_expr.type(), ns).has_value());
22582267
return simplify_expr(
22592268
typecast_exprt::conditional_cast(
22602269
extractbits_exprt{
@@ -2301,6 +2310,10 @@ exprt lower_byte_update(const byte_update_exprt &src, const namespacet &ns)
23012310
CHECK_RETURN(update_size_expr_opt.has_value());
23022311
simplify(update_size_expr_opt.value(), ns);
23032312

2313+
const irep_idt extract_opcode = src.id() == ID_byte_update_little_endian
2314+
? ID_byte_extract_little_endian
2315+
: ID_byte_extract_big_endian;
2316+
23042317
if(!update_size_expr_opt.value().is_constant())
23052318
non_const_update_bound = *update_size_expr_opt;
23062319
else
@@ -2318,14 +2331,21 @@ exprt lower_byte_update(const byte_update_exprt &src, const namespacet &ns)
23182331
DATA_INVARIANT(
23192332
can_cast_type<bitvector_typet>(update_value.type()),
23202333
"non-byte aligned type expected to be a bitvector type");
2321-
size_t n_extra_bits = 8 - update_bits_int % 8;
2334+
const byte_extract_exprt overlapping_byte_extract{
2335+
extract_opcode,
2336+
src.op(),
2337+
simplify_expr(
2338+
plus_exprt{
2339+
src.offset(),
2340+
from_integer(update_bits_int / 8, src.offset().type())},
2341+
ns),
2342+
bv_typet{8}};
2343+
const exprt overlapping_byte =
2344+
lower_byte_extract(overlapping_byte_extract, ns);
23222345

2323-
endianness_mapt endianness_map(
2324-
src.op().type(), src.id() == ID_byte_update_little_endian, ns);
2325-
const auto bounds = map_bounds(
2326-
endianness_map, update_bits_int, update_bits_int + n_extra_bits - 1);
2346+
size_t n_extra_bits = 8 - update_bits_int % 8;
23272347
extractbits_exprt extra_bits{
2328-
src.op(), bounds.ub, bounds.lb, bv_typet{n_extra_bits}};
2348+
overlapping_byte, n_extra_bits - 1, 0, bv_typet{n_extra_bits}};
23292349

23302350
update_value = concatenation_exprt{
23312351
typecast_exprt::conditional_cast(
@@ -2340,10 +2360,6 @@ exprt lower_byte_update(const byte_update_exprt &src, const namespacet &ns)
23402360
}
23412361
}
23422362

2343-
const irep_idt extract_opcode = src.id() == ID_byte_update_little_endian
2344-
? ID_byte_extract_little_endian
2345-
: ID_byte_extract_big_endian;
2346-
23472363
const byte_extract_exprt byte_extract_expr{
23482364
extract_opcode,
23492365
update_value,

0 commit comments

Comments
 (0)