Skip to content

Commit f4fb099

Browse files
committed
Fix process_array_expr to take into account pointer offset
1 parent 379705f commit f4fb099

File tree

5 files changed

+176
-233
lines changed

5 files changed

+176
-233
lines changed

regression/cbmc/memcpy2/main.c

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#include <assert.h>
2+
#include <string.h>
3+
4+
int main()
5+
{
6+
char A[3] = {'a', 'b', 'c'};
7+
char *p = A;
8+
char v1, v2;
9+
10+
memcpy(&v1, p, 1);
11+
++p;
12+
memcpy(&v2, p, 1);
13+
14+
assert(v1 == 'a');
15+
assert(v2 == 'b');
16+
17+
return 0;
18+
}

regression/cbmc/memcpy2/test.desc

+8
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/goto-symex/goto_symex.h

-1
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,6 @@ class goto_symext
252252
void trigger_auto_object(const exprt &, statet &);
253253
void initialize_auto_object(const exprt &, statet &);
254254
void process_array_expr(exprt &);
255-
void process_array_expr_rec(exprt &, const typet &) const;
256255
exprt make_auto_object(const typet &, statet &);
257256
virtual void dereference(exprt &, statet &, const bool write);
258257

src/goto-symex/symex_clean_expr.cpp

+67-96
Original file line numberDiff line numberDiff line change
@@ -15,77 +15,13 @@ Author: Daniel Kroening, [email protected]
1515
#include <util/std_expr.h>
1616
#include <util/cprover_prefix.h>
1717
#include <util/base_type.h>
18-
18+
#include <util/pointer_offset_size.h>
1919
#include <util/c_types.h>
2020

21-
void goto_symext::process_array_expr_rec(
22-
exprt &expr,
23-
const typet &type) const
24-
{
25-
if(expr.id()==ID_if)
26-
{
27-
if_exprt &if_expr=to_if_expr(expr);
28-
process_array_expr_rec(if_expr.true_case(), type);
29-
process_array_expr_rec(if_expr.false_case(), type);
30-
}
31-
else if(expr.id()==ID_index)
32-
{
33-
// strip index
34-
index_exprt &index_expr=to_index_expr(expr);
35-
exprt tmp=index_expr.array();
36-
expr.swap(tmp);
37-
}
38-
else if(expr.id()==ID_typecast)
39-
{
40-
// strip
41-
exprt tmp=to_typecast_expr(expr).op0();
42-
expr.swap(tmp);
43-
process_array_expr_rec(expr, type);
44-
}
45-
else if(expr.id()==ID_address_of)
46-
{
47-
// strip
48-
exprt tmp=to_address_of_expr(expr).op0();
49-
expr.swap(tmp);
50-
process_array_expr_rec(expr, type);
51-
}
52-
else if(expr.id()==ID_byte_extract_little_endian ||
53-
expr.id()==ID_byte_extract_big_endian)
54-
{
55-
// pick the root object
56-
exprt tmp=to_byte_extract_expr(expr).op();
57-
expr.swap(tmp);
58-
process_array_expr_rec(expr, type);
59-
}
60-
else if(expr.id()==ID_symbol &&
61-
expr.get_bool(ID_C_SSA_symbol) &&
62-
to_ssa_expr(expr).get_original_expr().id()==ID_index)
63-
{
64-
const ssa_exprt &ssa=to_ssa_expr(expr);
65-
const index_exprt &index_expr=to_index_expr(ssa.get_original_expr());
66-
exprt tmp=index_expr.array();
67-
expr.swap(tmp);
68-
}
69-
else
70-
{
71-
Forall_operands(it, expr)
72-
{
73-
typet t=it->type();
74-
process_array_expr_rec(*it, t);
75-
}
76-
}
77-
78-
if(!base_type_eq(expr.type(), type, ns))
79-
{
80-
byte_extract_exprt be(byte_extract_id());
81-
be.type()=type;
82-
be.op()=expr;
83-
be.offset()=from_integer(0, index_type());
84-
85-
expr.swap(be);
86-
}
87-
}
88-
21+
/// Given an expression, find the root object and the offset into it.
22+
///
23+
/// The extra complication to be considered here is that the expression may
24+
/// have any number of ternary expressions mixed with type casts.
8925
void goto_symext::process_array_expr(exprt &expr)
9026
{
9127
// This may change the type of the expression!
@@ -94,41 +30,28 @@ void goto_symext::process_array_expr(exprt &expr)
9430
{
9531
if_exprt &if_expr=to_if_expr(expr);
9632
process_array_expr(if_expr.true_case());
33+
process_array_expr(if_expr.false_case());
9734

98-
process_array_expr_rec(if_expr.false_case(),
99-
if_expr.true_case().type());
35+
if(!base_type_eq(if_expr.true_case(), if_expr.false_case(), ns))
36+
{
37+
byte_extract_exprt be(
38+
byte_extract_id(),
39+
if_expr.false_case(),
40+
from_integer(0, index_type()),
41+
if_expr.true_case().type());
42+
43+
if_expr.false_case().swap(be);
44+
}
10045

10146
if_expr.type()=if_expr.true_case().type();
10247
}
103-
else if(expr.id()==ID_index)
104-
{
105-
// strip index
106-
index_exprt &index_expr=to_index_expr(expr);
107-
exprt tmp=index_expr.array();
108-
expr.swap(tmp);
109-
}
110-
else if(expr.id()==ID_typecast)
111-
{
112-
// strip
113-
exprt tmp=to_typecast_expr(expr).op0();
114-
expr.swap(tmp);
115-
process_array_expr(expr);
116-
}
11748
else if(expr.id()==ID_address_of)
11849
{
11950
// strip
12051
exprt tmp=to_address_of_expr(expr).op0();
12152
expr.swap(tmp);
12253
process_array_expr(expr);
12354
}
124-
else if(expr.id()==ID_byte_extract_little_endian ||
125-
expr.id()==ID_byte_extract_big_endian)
126-
{
127-
// pick the root object
128-
exprt tmp=to_byte_extract_expr(expr).op();
129-
expr.swap(tmp);
130-
process_array_expr(expr);
131-
}
13255
else if(expr.id()==ID_symbol &&
13356
expr.get_bool(ID_C_SSA_symbol) &&
13457
to_ssa_expr(expr).get_original_expr().id()==ID_index)
@@ -137,10 +60,58 @@ void goto_symext::process_array_expr(exprt &expr)
13760
const index_exprt &index_expr=to_index_expr(ssa.get_original_expr());
13861
exprt tmp=index_expr.array();
13962
expr.swap(tmp);
63+
64+
process_array_expr(expr);
65+
}
66+
else if(expr.id() != ID_symbol)
67+
{
68+
object_descriptor_exprt ode;
69+
ode.build(expr, ns);
70+
do_simplify(ode.offset());
71+
72+
expr = ode.root_object();
73+
74+
if(!ode.offset().is_zero())
75+
{
76+
if(expr.type().id() != ID_array)
77+
{
78+
exprt array_size = size_of_expr(expr.type(), ns);
79+
do_simplify(array_size);
80+
expr =
81+
byte_extract_exprt(
82+
byte_extract_id(),
83+
expr,
84+
from_integer(0, index_type()),
85+
array_typet(char_type(), array_size));
86+
}
87+
88+
// given an array type T[N], i.e., an array of N elements of type T, and a
89+
// byte offset B, compute the array offset B/sizeof(T) and build a new
90+
// type T[N-(B/sizeof(T))]
91+
const array_typet &prev_array_type = to_array_type(expr.type());
92+
const typet &array_size_type = prev_array_type.size().type();
93+
const typet &subtype = prev_array_type.subtype();
94+
95+
exprt new_offset(ode.offset());
96+
if(new_offset.type() != array_size_type)
97+
new_offset.make_typecast(array_size_type);
98+
exprt subtype_size = size_of_expr(subtype, ns);
99+
if(subtype_size.type() != array_size_type)
100+
subtype_size.make_typecast(array_size_type);
101+
new_offset = div_exprt(new_offset, subtype_size);
102+
minus_exprt new_size(prev_array_type.size(), new_offset);
103+
do_simplify(new_size);
104+
105+
array_typet new_array_type(subtype, new_size);
106+
107+
expr =
108+
byte_extract_exprt(
109+
byte_extract_id(),
110+
expr,
111+
ode.offset(),
112+
new_array_type);
113+
}
140114
}
141-
else
142-
Forall_operands(it, expr)
143-
process_array_expr(*it);
144115
}
145116

146117
/// Rewrite index/member expressions in byte_extract to offset

0 commit comments

Comments
 (0)