Skip to content

Commit 4a8b5ec

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 fe4e10c commit 4a8b5ec

File tree

4 files changed

+37
-5
lines changed

4 files changed

+37
-5
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$

regression/cbmc/havoc_slice/test_struct_b_slice.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
test_struct_b_slice.c
33

44
^EXIT=10$

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
@@ -2278,20 +2278,51 @@ exprt lower_byte_update(const byte_update_exprt &src, const namespacet &ns)
22782278
// place.
22792279
// 4) Construct a new object.
22802280
optionalt<exprt> non_const_update_bound;
2281-
auto update_size_expr_opt = size_of_expr(src.value().type(), ns);
2281+
// update value, may require extension to full bytes
2282+
exprt update_value = src.value();
2283+
auto update_size_expr_opt = size_of_expr(update_value.type(), ns);
22822284
CHECK_RETURN(update_size_expr_opt.has_value());
22832285
simplify(update_size_expr_opt.value(), ns);
22842286

22852287
if(!update_size_expr_opt.value().is_constant())
22862288
non_const_update_bound = *update_size_expr_opt;
2289+
else
2290+
{
2291+
auto update_bits = pointer_offset_bits(update_value.type(), ns);
2292+
DATA_INVARIANT(
2293+
update_bits.has_value(), "constant size-of should imply fixed bit width");
2294+
const size_t update_bits_int = numeric_cast_v<size_t>(*update_bits);
2295+
2296+
if(update_bits_int % 8 != 0)
2297+
{
2298+
DATA_INVARIANT(
2299+
can_cast_type<bitvector_typet>(update_value.type()),
2300+
"non-byte aligned type expected to be a bitvector type");
2301+
size_t n_extra_bits = 8 - update_bits_int % 8;
2302+
2303+
endianness_mapt endianness_map(
2304+
src.op().type(), src.id() == ID_byte_update_little_endian, ns);
2305+
const auto bounds = map_bounds(
2306+
endianness_map, update_bits_int, update_bits_int + n_extra_bits - 1);
2307+
extractbits_exprt extra_bits{
2308+
src.op(), bounds.ub, bounds.lb, bv_typet{n_extra_bits}};
2309+
2310+
update_value =
2311+
concatenation_exprt{typecast_exprt::conditional_cast(
2312+
update_value, bv_typet{update_bits_int}),
2313+
extra_bits,
2314+
bitvector_typet{update_value.type().id(),
2315+
update_bits_int + n_extra_bits}};
2316+
}
2317+
}
22872318

22882319
const irep_idt extract_opcode = src.id() == ID_byte_update_little_endian
22892320
? ID_byte_extract_little_endian
22902321
: ID_byte_extract_big_endian;
22912322

22922323
const byte_extract_exprt byte_extract_expr{
22932324
extract_opcode,
2294-
src.value(),
2325+
update_value,
22952326
from_integer(0, src.offset().type()),
22962327
array_typet{bv_typet{8}, *update_size_expr_opt}};
22972328

0 commit comments

Comments
 (0)