Skip to content

Commit bc1012b

Browse files
authored
Merge pull request #7045 from tautschnig/bugfixes/7036-array-ops
Remove well-alignedness assumption from pointer dereferencing
2 parents 52b1b40 + 6633948 commit bc1012b

File tree

4 files changed

+81
-30
lines changed

4 files changed

+81
-30
lines changed
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#include <assert.h>
2+
3+
typedef struct my_struct
4+
{
5+
char a;
6+
char b;
7+
char c[5];
8+
} my_struct;
9+
10+
int main()
11+
{
12+
my_struct arr[3] = {0};
13+
char *ptr = &(arr[1].c[2]);
14+
int offset;
15+
__CPROVER_assume(offset < 1 && offset > -1);
16+
void *ptr_plus = ptr + offset;
17+
char nondet[3];
18+
19+
__CPROVER_array_replace(ptr_plus, &nondet[0]);
20+
21+
// expected valid and proved
22+
assert(arr[0].a == 0);
23+
assert(arr[0].b == 0);
24+
assert(arr[0].c[0] == 0);
25+
assert(arr[0].c[1] == 0);
26+
assert(arr[0].c[2] == 0);
27+
assert(arr[0].c[3] == 0);
28+
assert(arr[0].c[4] == 0);
29+
30+
assert(arr[1].a == 0); // expected valid, falsified
31+
assert(arr[1].b == 0); // expected valid, falsified
32+
assert(arr[1].c[0] == 0); // expected valid, falsified
33+
assert(arr[1].c[1] == 0); // expected valid, proved
34+
assert(arr[1].c[2] == 0); // expected falsifiable, proved
35+
assert(arr[1].c[3] == 0); // expected falsifiable, proved
36+
assert(arr[1].c[4] == 0); // expected falsifiable, proved
37+
38+
// expected valid and proved
39+
assert(arr[2].a == 0);
40+
assert(arr[2].b == 0);
41+
assert(arr[2].c[0] == 0);
42+
assert(arr[2].c[1] == 0);
43+
assert(arr[2].c[2] == 0);
44+
assert(arr[2].c[3] == 0);
45+
assert(arr[2].c[4] == 0);
46+
47+
return 0;
48+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
CORE broken-smt-backend
2+
main.c
3+
4+
^\[main.assertion.12\] line 34 assertion arr\[1\].c\[2\] == 0: FAILURE$
5+
^\[main.assertion.13\] line 35 assertion arr\[1\].c\[3\] == 0: FAILURE$
6+
^\[main.assertion.14\] line 36 assertion arr\[1\].c\[4\] == 0: FAILURE$
7+
^\*\* 3 of 21 failed
8+
^VERIFICATION FAILED$
9+
^EXIT=10$
10+
^SIGNAL=0$
11+
--
12+
^warning: ignoring
13+
--
14+
Verify the properties of various cprover array primitves

src/pointer-analysis/value_set_dereference.cpp

Lines changed: 19 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -99,9 +99,11 @@ static json_objectt value_set_dereference_stats_to_json(
9999
return json_result;
100100
}
101101

102-
optionalt<exprt> value_set_dereferencet::try_add_offset_to_indices(
103-
const exprt &expr,
104-
const exprt &offset_elements)
102+
/// If `expr` is of the form (c1 ? e1[o1] : c2 ? e2[o2] : c3 ? ...)
103+
/// then return `c1 ? e1[o1 + offset] : e2[o2 + offset] : c3 ? ...`
104+
/// otherwise return an empty optionalt.
105+
static optionalt<exprt>
106+
try_add_offset_to_indices(const exprt &expr, const exprt &offset_elements)
105107
{
106108
if(const auto *index_expr = expr_try_dynamic_cast<index_exprt>(expr))
107109
{
@@ -123,6 +125,13 @@ optionalt<exprt> value_set_dereferencet::try_add_offset_to_indices(
123125
return {};
124126
return if_exprt{if_expr->cond(), *true_case, *false_case};
125127
}
128+
else if(can_cast_expr<typecast_exprt>(expr))
129+
{
130+
// the case of a type cast is _not_ handled here, because that would require
131+
// doing arithmetic on the offset, and may result in an offset into some
132+
// sub-element
133+
return {};
134+
}
126135
else
127136
{
128137
return {};
@@ -572,12 +581,12 @@ value_set_dereferencet::valuet value_set_dereferencet::build_reference_to(
572581
else if(
573582
root_object_type.id() == ID_array &&
574583
dereference_type_compare(
575-
to_array_type(root_object_type).element_type(), dereference_type, ns))
584+
to_array_type(root_object_type).element_type(), dereference_type, ns) &&
585+
pointer_offset_bits(to_array_type(root_object_type).element_type(), ns) ==
586+
pointer_offset_bits(dereference_type, ns))
576587
{
577588
// We have an array with a subtype that matches
578589
// the dereferencing type.
579-
// We will require well-alignedness!
580-
581590
exprt offset;
582591

583592
// this should work as the object is essentially the root object
@@ -586,8 +595,6 @@ value_set_dereferencet::valuet value_set_dereferencet::build_reference_to(
586595
else
587596
offset=pointer_offset(pointer_expr);
588597

589-
exprt adjusted_offset;
590-
591598
// are we doing a byte?
592599
auto element_size =
593600
pointer_offset_size(to_array_type(root_object_type).element_type(), ns);
@@ -597,25 +604,13 @@ value_set_dereferencet::valuet value_set_dereferencet::build_reference_to(
597604
throw "unknown or invalid type size of:\n" +
598605
to_array_type(root_object_type).element_type().pretty();
599606
}
600-
else if(*element_size == 1)
601-
{
602-
// no need to adjust offset
603-
adjusted_offset = offset;
604-
}
605-
else
606-
{
607-
exprt element_size_expr = from_integer(*element_size, offset.type());
608607

609-
adjusted_offset=binary_exprt(
610-
offset, ID_div, element_size_expr, offset.type());
608+
exprt element_size_expr = from_integer(*element_size, offset.type());
611609

612-
// TODO: need to assert well-alignedness
613-
}
610+
exprt adjusted_offset =
611+
simplify_expr(div_exprt{offset, element_size_expr}, ns);
614612

615-
const index_exprt &index_expr = index_exprt(
616-
root_object,
617-
adjusted_offset,
618-
to_array_type(root_object_type).element_type());
613+
index_exprt index_expr{root_object, adjusted_offset};
619614
result.value =
620615
typecast_exprt::conditional_cast(index_expr, dereference_type);
621616
result.pointer = typecast_exprt::conditional_cast(

src/pointer-analysis/value_set_dereference.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,6 @@ class value_set_dereferencet final
5454
/// \param display_points_to_sets: Display size and contents of points to sets
5555
exprt dereference(const exprt &pointer, bool display_points_to_sets = false);
5656

57-
/// If `expr` is of the form (c1 ? e1[o1] : c2 ? e2[o2] : c3 ? ...)
58-
/// then return `c1 ? e1[o1 + offset] : e2[o2 + offset] : c3 ? ...`
59-
/// otherwise return an empty optionalt.
60-
optionalt<exprt>
61-
try_add_offset_to_indices(const exprt &expr, const exprt &offset);
62-
6357
/// Return value for `build_reference_to`; see that method for documentation.
6458
class valuet
6559
{

0 commit comments

Comments
 (0)