Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions regression/cbmc/byte_update_sub_byte1/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
int main()
{
unsigned x;
__CPROVER_bitvector[1] *p = (__CPROVER_bitvector[1] *)&x;
*p = 0;
__CPROVER_assert((x & 0x80u) == 0u, "MSB of byte 0 is cleared");
}
11 changes: 11 additions & 0 deletions regression/cbmc/byte_update_sub_byte1/symbolic-offset.desc
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
CORE
symbolic.c
--little-endian --no-simplify
^VERIFICATION SUCCESSFUL$
^EXIT=0$
^SIGNAL=0$
--
^warning: ignoring
--
Same as test.desc but with a symbolic (constrained-to-0) byte offset,
exercising the variable-offset branch of convert_byte_update.
9 changes: 9 additions & 0 deletions regression/cbmc/byte_update_sub_byte1/symbolic.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
int main()
{
unsigned x;
unsigned offset;
__CPROVER_assume(offset == 0);
__CPROVER_bitvector[1] *p = (__CPROVER_bitvector[1] *)((char *)&x + offset);
*p = 0;
__CPROVER_assert((x & 0x80u) == 0u, "MSB of byte 0 is cleared");
}
13 changes: 13 additions & 0 deletions regression/cbmc/byte_update_sub_byte1/test.desc
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
CORE
main.c
--little-endian --no-simplify
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We really need to find a better mechanism to test these things that does not involve turning off the simplifier.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but this is just another example where the simplifier pretty much does what the back-end would otherwise do. In other words: I was not able to create a test that the simplifier wouldn't already rewrite to an expression that does not have the corner case that's being tackled here.

^VERIFICATION SUCCESSFUL$
^EXIT=0$
Comment thread
tautschnig marked this conversation as resolved.
^SIGNAL=0$
--
^warning: ignoring
--
Writing a 1-bit zero through a __CPROVER_bitvector[1] pointer must
clear the MSB of the first byte, not the LSB. The --no-simplify flag
is needed to exercise the boolbv convert_byte_update path directly.
This test uses a constant offset (byte 0).
22 changes: 19 additions & 3 deletions src/solvers/flattening/boolbv_byte_update.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,22 @@ bvt boolbvt::convert_byte_update(const byte_update_exprt &expr)
if(update_width>bv.size())
update_width=bv.size();

// When the update value is not a multiple of the byte width,
// lower_byte_update places the value at the high end of the last partial
// byte (concatenating {value, remaining_low_bits}). For little-endian the
// high end is at higher bit indices, so we shift the trailing partial
// byte's bits up. For big-endian the endianness map already places bit 0
// at the MSB, so no shift is needed.
const std::size_t tail_bits = update_width % byte_width;
const std::size_t tail_shift =
little_endian && tail_bits != 0 ? byte_width - tail_bits : 0;

// For a given bit index i (0-based within the update value), compute the
// additional offset to place trailing partial-byte bits at the high end.
auto bit_shift = [&](std::size_t i) -> std::size_t {
return (tail_shift != 0 && i >= update_width - tail_bits) ? tail_shift : 0;
};

// see if the byte number is constant

const auto index = numeric_cast<mp_integer>(offset_expr);
Expand All @@ -62,7 +78,7 @@ bvt boolbvt::convert_byte_update(const byte_update_exprt &expr)

for(std::size_t i = 0; i < update_width; i++)
{
size_t index_op = map_op.map_bit(offset_i + i);
size_t index_op = map_op.map_bit(offset_i + bit_shift(i) + i);
size_t index_value = map_value.map_bit(i);

INVARIANT(
Expand Down Expand Up @@ -90,9 +106,9 @@ bvt boolbvt::convert_byte_update(const byte_update_exprt &expr)
endianness_mapt map_value = endianness_map(value.type(), little_endian);

for(std::size_t bit=0; bit<update_width; bit++)
if(offset+bit<bv.size())
if(offset + bit_shift(bit) + bit < bv.size())
{
std::size_t bv_o=map_op.map_bit(offset+bit);
std::size_t bv_o = map_op.map_bit(offset + bit_shift(bit) + bit);
std::size_t value_bv_o=map_value.map_bit(bit);

bv[bv_o]=prop.lselect(equal, value_bv[value_bv_o], bv[bv_o]);
Expand Down
Loading