Skip to content

Commit 050dc14

Browse files
committed
Byte updates using bit fields require extension to full bytes
A byte update with an update value that has a size that's not a multiple of bytes must not overwrite bits that are not in the update value. We previously generated extractbits expressions that would go out of bounds, which tripped up the SMT solvers. No longer generating these out-of-bounds expressions makes the SMT solvers happy on the Promotion3 test, which exercised this feature.
1 parent e6b3118 commit 050dc14

File tree

3 files changed

+36
-4
lines changed

3 files changed

+36
-4
lines changed

regression/cbmc/Promotion3/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$

src/goto-programs/builtin_functions.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ Author: Daniel Kroening, [email protected]
2222
#include <util/prefix.h>
2323
#include <util/rational.h>
2424
#include <util/rational_tools.h>
25+
#include <util/simplify_expr.h>
2526
#include <util/symbol_table.h>
2627

2728
#include <langapi/language_util.h>
@@ -699,7 +700,7 @@ void goto_convertt::do_havoc_slice(
699700
t->source_location_nonconst().set_comment(
700701
"assertion havoc_slice " + from_expr(ns, identifier, ok_expr));
701702

702-
const array_typet array_type(char_type(), arguments[1]);
703+
const array_typet array_type(char_type(), simplify_expr(arguments[1], ns));
703704

704705
const symbolt &nondet_contents =
705706
new_tmp_symbol(array_type, "nondet_contents", dest, source_location, mode);

src/solvers/lowering/byte_operators.cpp

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2261,20 +2261,51 @@ exprt lower_byte_update(const byte_update_exprt &src, const namespacet &ns)
22612261
// place.
22622262
// 4) Construct a new object.
22632263
optionalt<exprt> non_const_update_bound;
2264-
auto update_size_expr_opt = size_of_expr(src.value().type(), ns);
2264+
// update value, may require extension to full bytes
2265+
exprt update_value = src.value();
2266+
auto update_size_expr_opt = size_of_expr(update_value.type(), ns);
22652267
CHECK_RETURN(update_size_expr_opt.has_value());
22662268
simplify(update_size_expr_opt.value(), ns);
22672269

22682270
if(!update_size_expr_opt.value().is_constant())
22692271
non_const_update_bound = *update_size_expr_opt;
2272+
else
2273+
{
2274+
auto update_bits = pointer_offset_bits(update_value.type(), ns);
2275+
DATA_INVARIANT(
2276+
update_bits.has_value(), "constant size-of should imply fixed bit width");
2277+
const size_t update_bits_int = numeric_cast_v<size_t>(*update_bits);
2278+
2279+
if(update_bits_int % 8 != 0)
2280+
{
2281+
DATA_INVARIANT(
2282+
can_cast_type<bitvector_typet>(update_value.type()),
2283+
"non-byte aligned type expected to be a bitvector type");
2284+
size_t n_extra_bits = 8 - update_bits_int % 8;
2285+
2286+
endianness_mapt endianness_map(
2287+
src.op().type(), src.id() == ID_byte_update_little_endian, ns);
2288+
const auto bounds = map_bounds(
2289+
endianness_map, update_bits_int, update_bits_int + n_extra_bits - 1);
2290+
extractbits_exprt extra_bits{
2291+
src.op(), bounds.ub, bounds.lb, bv_typet{n_extra_bits}};
2292+
2293+
update_value =
2294+
concatenation_exprt{typecast_exprt::conditional_cast(
2295+
update_value, bv_typet{update_bits_int}),
2296+
extra_bits,
2297+
bitvector_typet{update_value.type().id(),
2298+
update_bits_int + n_extra_bits}};
2299+
}
2300+
}
22702301

22712302
const irep_idt extract_opcode = src.id() == ID_byte_update_little_endian
22722303
? ID_byte_extract_little_endian
22732304
: ID_byte_extract_big_endian;
22742305

22752306
const byte_extract_exprt byte_extract_expr{
22762307
extract_opcode,
2277-
src.value(),
2308+
update_value,
22782309
from_integer(0, src.offset().type()),
22792310
array_typet{bv_typet{8}, *update_size_expr_opt}};
22802311

0 commit comments

Comments
 (0)