Skip to content

Commit 54411e0

Browse files
committed
Byte-update lowering: handle sub-byte sized bit fields
Extend the value to be updated to the update size immediately to avoid extractbits operations that attempt to extract bits that do not exist. Fixes: #5389
1 parent df2638c commit 54411e0

File tree

3 files changed

+56
-20
lines changed

3 files changed

+56
-20
lines changed

regression/cbmc/byte_update13/main.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#include <assert.h>
2+
#include <string.h>
3+
4+
struct blob
5+
{
6+
unsigned dummy;
7+
unsigned bit : 1;
8+
};
9+
10+
int main()
11+
{
12+
struct blob b;
13+
struct blob b1 = b;
14+
15+
if(b.dummy <= sizeof(struct blob))
16+
memset(&b, 0, b.dummy);
17+
18+
assert(b1.dummy != sizeof(struct blob) || b.bit == 0);
19+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
main.c
3+
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
^warning: ignoring

src/solvers/lowering/byte_operators.cpp

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2136,10 +2136,30 @@ static exprt lower_byte_update(
21362136
instantiate_byte_array(value_as_byte_array, 0, (type_bits + 7) / 8, ns);
21372137
}
21382138

2139+
const std::size_t update_size = update_bytes.size();
2140+
const std::size_t width = std::max(type_bits, update_size * 8);
2141+
2142+
const bool is_little_endian = src.id() == ID_byte_update_little_endian;
2143+
2144+
exprt val_before =
2145+
typecast_exprt::conditional_cast(src.op(), bv_typet{type_bits});
2146+
if(width > type_bits)
2147+
{
2148+
val_before =
2149+
concatenation_exprt{from_integer(0, bv_typet{width - type_bits}),
2150+
val_before,
2151+
bv_typet{width}};
2152+
2153+
if(!is_little_endian)
2154+
to_concatenation_expr(val_before)
2155+
.op0()
2156+
.swap(to_concatenation_expr(val_before).op1());
2157+
}
2158+
21392159
if(non_const_update_bound.has_value())
21402160
{
21412161
const exprt src_as_bytes = unpack_rec(
2142-
src.op(),
2162+
val_before,
21432163
src.id() == ID_byte_update_little_endian,
21442164
mp_integer{0},
21452165
mp_integer{update_bytes.size()},
@@ -2158,11 +2178,6 @@ static exprt lower_byte_update(
21582178
}
21592179
}
21602180

2161-
const std::size_t update_size = update_bytes.size();
2162-
const std::size_t width = std::max(type_bits, update_size * 8);
2163-
2164-
const bool is_little_endian = src.id() == ID_byte_update_little_endian;
2165-
21662181
// build mask
21672182
exprt mask;
21682183
if(is_little_endian)
@@ -2186,20 +2201,6 @@ static exprt lower_byte_update(
21862201
mask_shifted.true_case().swap(mask_shifted.false_case());
21872202

21882203
// original_bits &= ~mask
2189-
exprt val_before =
2190-
typecast_exprt::conditional_cast(src.op(), bv_typet{type_bits});
2191-
if(width > type_bits)
2192-
{
2193-
val_before =
2194-
concatenation_exprt{from_integer(0, bv_typet{width - type_bits}),
2195-
val_before,
2196-
bv_typet{width}};
2197-
2198-
if(!is_little_endian)
2199-
to_concatenation_expr(val_before)
2200-
.op0()
2201-
.swap(to_concatenation_expr(val_before).op1());
2202-
}
22032204
bitand_exprt bitand_expr{val_before, bitnot_exprt{mask_shifted}};
22042205

22052206
// concatenate and zero-extend the value
@@ -2242,6 +2243,14 @@ static exprt lower_byte_update(
22422243
src.type()),
22432244
ns);
22442245
}
2246+
else if(width > type_bits)
2247+
{
2248+
return simplify_expr(
2249+
typecast_exprt::conditional_cast(
2250+
extractbits_exprt{bitor_expr, type_bits - 1, 0, bv_typet{type_bits}},
2251+
src.type()),
2252+
ns);
2253+
}
22452254

22462255
return simplify_expr(
22472256
typecast_exprt::conditional_cast(bitor_expr, src.type()), ns);

0 commit comments

Comments
 (0)