Skip to content

Commit 7bae4d5

Browse files
committed
Byte-operator lowering: Add support for byte-extracting unions
We already had support for structs, arrays, vectors in place; add unions following the same approach. This is required for some SV-COMP device driver benchmarks, including ldv-linux-3.16-rc1/43_2a_consumption_linux-3.16-rc1.tar.xz-43_2a-drivers--scsi--qla2xxx--tcm_qla2xxx.ko-entry_point.cil.out.i Adding a test also made apparent that we weren't yet handling unbounded byte extracts (out of a bounded object) in flattening.
1 parent abd2628 commit 7bae4d5

File tree

4 files changed

+77
-1
lines changed

4 files changed

+77
-1
lines changed

regression/cbmc/union14/main.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
int main()
2+
{
3+
unsigned x;
4+
__CPROVER_assume(x > 0);
5+
union U {
6+
char A[x];
7+
};
8+
int i, i_before;
9+
i_before = i;
10+
union U u = *((union U *)&i);
11+
i = u.A[0];
12+
__CPROVER_assert(i == i_before, "going through union works");
13+
}

regression/cbmc/union14/test.desc

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/flattening/boolbv_byte_extract.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ bvt boolbvt::convert_byte_extract(const byte_extract_exprt &expr)
4343
{
4444
// array logic does not handle byte operators, thus lower when operating on
4545
// unbounded arrays
46-
if(is_unbounded_array(expr.op().type()))
46+
if(is_unbounded_array(expr.op().type()) || is_unbounded_array(expr.type()))
4747
{
4848
try
4949
{

src/solvers/lowering/byte_operators.cpp

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,46 @@ static struct_exprt bv_to_struct_expr(
108108
return struct_exprt{std::move(operands), struct_type};
109109
}
110110

111+
/// Convert a bitvector-typed expression \p bitvector_expr to a union-typed
112+
/// expression. See \ref bv_to_expr for an overview.
113+
static union_exprt bv_to_union_expr(
114+
const exprt &bitvector_expr,
115+
const union_typet &union_type,
116+
const endianness_mapt &endianness_map,
117+
const namespacet &ns)
118+
{
119+
const union_typet::componentst &components = union_type.components();
120+
121+
if(components.empty())
122+
{
123+
// deal with empty unions the same way zero_initializer does
124+
return union_exprt{irep_idt{}, nil_exprt{}, union_type};
125+
}
126+
127+
// we will use the first component, unless we can find a member that
128+
// definitively is larger
129+
mp_integer max_width = 0;
130+
typet max_comp_type = components.front().type();
131+
irep_idt max_comp_name = components.front().get_name();
132+
133+
for(const auto &comp : components)
134+
{
135+
auto element_width = pointer_offset_bits(comp.type(), ns);
136+
137+
if(!element_width.has_value() || *element_width <= max_width)
138+
continue;
139+
140+
max_width = *element_width;
141+
max_comp_type = comp.type();
142+
max_comp_name = comp.get_name();
143+
}
144+
145+
return union_exprt{
146+
std::move(max_comp_name),
147+
bv_to_expr(bitvector_expr, max_comp_type, endianness_map, ns),
148+
union_type};
149+
}
150+
111151
/// Convert a bitvector-typed expression \p bitvector_expr to an array-typed
112152
/// expression. See \ref bv_to_expr for an overview.
113153
static array_exprt bv_to_array_expr(
@@ -296,6 +336,21 @@ static exprt bv_to_expr(
296336
result.type() = target_type;
297337
return std::move(result);
298338
}
339+
else if(target_type.id() == ID_union)
340+
{
341+
return bv_to_union_expr(
342+
bitvector_expr, to_union_type(target_type), endianness_map, ns);
343+
}
344+
else if(target_type.id() == ID_union_tag)
345+
{
346+
union_exprt result = bv_to_union_expr(
347+
bitvector_expr,
348+
ns.follow_tag(to_union_tag_type(target_type)),
349+
endianness_map,
350+
ns);
351+
result.type() = target_type;
352+
return std::move(result);
353+
}
299354
else if(target_type.id() == ID_array)
300355
{
301356
return bv_to_array_expr(

0 commit comments

Comments
 (0)