Skip to content

Commit 36562bc

Browse files
author
Daniel Kroening
authored
Merge pull request #126 from tautschnig/malloc-bugfix
malloc(sizeof(T)*n) for non-const n should still yield an array of subtype T
2 parents 79d9fbe + 057b0ba commit 36562bc

File tree

10 files changed

+136
-62
lines changed

10 files changed

+136
-62
lines changed

regression/cbmc/Malloc22/main.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#include <assert.h>
2+
#include <stdlib.h>
3+
4+
unsigned nondet_unsigned();
5+
6+
int main() {
7+
unsigned n = nondet_unsigned();
8+
__CPROVER_assume(n>0);
9+
unsigned pA[n];
10+
unsigned *p = (unsigned *)malloc(sizeof(unsigned) * n);
11+
12+
for (int i=0; i<n; i++) {
13+
p[i] = i;
14+
pA[i] = i;
15+
}
16+
assert(p[n-1] == n-1);
17+
assert(pA[n-1] == n-1);
18+
assert(0);
19+
20+
return 0;
21+
}
22+

regression/cbmc/Malloc22/test.desc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
CORE
2+
main.c
3+
--unwind 2 --smt2 --outfile main.smt2
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
--
7+
^Invalid expression: failed to get width of byte_update

regression/cbmc/big-endian-array1/main.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,13 @@ int main()
1515

1616
char *p=(char *)array;
1717
char p0=p[0];
18+
char p1=p[1];
19+
char p2=p[2];
20+
char p3=p[3];
1821
__CPROVER_assert(p0==1, "p[0] matches");
22+
__CPROVER_assert(p1==2, "p[1] matches");
23+
__CPROVER_assert(p2==3, "p[2] matches");
24+
__CPROVER_assert(p3==4, "p[3] matches");
1925

2026
unsigned short *q=(unsigned short *)array;
2127
unsigned short q0=q[0];

src/ansi-c/expr2c.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1914,6 +1914,15 @@ std::string expr2ct::convert_symbol(
19141914
}
19151915

19161916
dest=id2string(entry->second);
1917+
1918+
#if 0
1919+
if(has_prefix(id2string(id), "symex_dynamic::dynamic_object"))
1920+
{
1921+
if(sizeof_nesting++ == 0)
1922+
dest+=" /*"+convert(src.type());
1923+
if(--sizeof_nesting == 0) dest+="*/";
1924+
}
1925+
#endif
19171926
}
19181927

19191928
if(src.id()==ID_next_symbol)

src/goto-symex/symex_builtin_functions.cpp

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,26 @@ void goto_symext::symex_malloc(
9494
// Did the size get multiplied?
9595
mp_integer elem_size=pointer_offset_size(tmp_type, ns);
9696
mp_integer alloc_size;
97-
if(elem_size<0 || to_integer(tmp_size, alloc_size))
97+
98+
if(elem_size<0)
99+
{
100+
}
101+
else if(to_integer(tmp_size, alloc_size) &&
102+
tmp_size.id()==ID_mult &&
103+
tmp_size.operands().size()==2 &&
104+
(tmp_size.op0().is_constant() ||
105+
tmp_size.op1().is_constant()))
98106
{
107+
exprt s=tmp_size.op0();
108+
if(s.is_constant())
109+
{
110+
s=tmp_size.op1();
111+
assert(c_sizeof_type_rec(tmp_size.op0())==tmp_type);
112+
}
113+
else
114+
assert(c_sizeof_type_rec(tmp_size.op1())==tmp_type);
115+
116+
object_type=array_typet(tmp_type, s);
99117
}
100118
else
101119
{

src/solvers/flattening/flatten_byte_operators.cpp

Lines changed: 50 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ Author: Daniel Kroening, [email protected]
1111
#include <util/std_expr.h>
1212
#include <util/arith_tools.h>
1313
#include <util/pointer_offset_size.h>
14+
#include <util/byte_operators.h>
15+
#include <util/namespace.h>
1416

1517
#include "flatten_byte_operators.h"
1618

@@ -28,11 +30,9 @@ Function: flatten_byte_extract
2830
\*******************************************************************/
2931

3032
exprt flatten_byte_extract(
31-
const exprt &src,
33+
const byte_extract_exprt &src,
3234
const namespacet &ns)
3335
{
34-
assert(src.id()==ID_byte_extract_little_endian ||
35-
src.id()==ID_byte_extract_big_endian);
3636
assert(src.operands().size()==2);
3737

3838
bool little_endian;
@@ -47,39 +47,45 @@ exprt flatten_byte_extract(
4747
mp_integer size_bits=pointer_offset_bits(src.type(), ns);
4848
if(size_bits<0)
4949
throw "byte_extract flatting with non-constant size: "+src.pretty();
50-
std::size_t width_bits=integer2unsigned(size_bits);
51-
52-
std::size_t width_bytes=width_bits/8+(width_bits%8==0?0:1);
53-
54-
const typet &t=src.op0().type();
5550

56-
if(t.id()==ID_array)
51+
if(src.op0().type().id()==ID_array)
5752
{
58-
const array_typet &array_type=to_array_type(t);
53+
const exprt &root=src.op0();
54+
const exprt &offset=src.op1();
55+
56+
const array_typet &array_type=to_array_type(root.type());
5957
const typet &subtype=array_type.subtype();
58+
59+
mp_integer element_width=pointer_offset_bits(subtype, ns);
60+
if(element_width<0) // failed
61+
throw "failed to flatten array with unknown element width";
62+
63+
mp_integer num_elements=
64+
size_bits/element_width+((size_bits%element_width==0)?0:1);
65+
66+
const typet &offset_type=ns.follow(offset.type());
6067

6168
// byte-array?
62-
if((subtype.id()==ID_unsignedbv ||
63-
subtype.id()==ID_signedbv) &&
64-
to_bitvector_type(subtype).get_width()==8)
69+
if(element_width==8)
6570
{
6671
// get 'width'-many bytes, and concatenate
72+
std::size_t width_bytes=integer2unsigned(num_elements);
6773
exprt::operandst op;
68-
op.resize(width_bytes);
74+
op.reserve(width_bytes);
6975

7076
for(std::size_t i=0; i<width_bytes; i++)
7177
{
7278
// the most significant byte comes first in the concatenation!
73-
std::size_t offset_i=
79+
std::size_t offset_int=
7480
little_endian?(width_bytes-i-1):i;
7581

76-
plus_exprt offset(from_integer(offset_i, src.op1().type()), src.op1());
77-
index_exprt index_expr(subtype);
78-
index_expr.array()=src.op0();
79-
index_expr.index()=offset;
80-
op[i]=index_expr;
82+
plus_exprt offset_i(from_integer(offset_int, offset_type), offset);
83+
index_exprt index_expr(root, offset_i);
84+
op.push_back(index_expr);
8185
}
8286

87+
// TODO this doesn't seem correct if size_bits%8!=0 as more
88+
// bits than the original expression will be returned.
8389
if(width_bytes==1)
8490
return op[0];
8591
else // width_bytes>=2
@@ -91,44 +97,36 @@ exprt flatten_byte_extract(
9197
}
9298
else // non-byte array
9399
{
94-
const exprt &root=src.op0();
95-
const exprt &offset=src.op1();
96-
const typet &array_type=ns.follow(root.type());
97-
const typet &offset_type=ns.follow(offset.type());
98-
const typet &element_type=ns.follow(array_type.subtype());
99-
mp_integer element_width=pointer_offset_size(element_type, ns);
100-
101-
if(element_width==-1) // failed
102-
throw "failed to flatten non-byte array with unknown element width";
103-
104-
mp_integer result_width=pointer_offset_size(src.type(), ns);
105-
mp_integer num_elements=(element_width+result_width-2)/element_width+1;
100+
// add an extra element as the access need not be aligned with
101+
// element boundaries and could thus stretch over extra elements
102+
++num_elements;
106103

107104
// compute new root and offset
108105
concatenation_exprt concat(
109-
unsignedbv_typet(integer2unsigned(element_width*8*num_elements)));
106+
unsignedbv_typet(integer2unsigned(element_width*num_elements)));
110107

108+
assert(element_width%8==0);
111109
exprt first_index=
112-
(element_width==1)?offset
113-
: div_exprt(offset, from_integer(element_width, offset_type)); // 8*offset/el_w
110+
div_exprt(offset, from_integer(element_width/8, offset_type));
114111

115-
for(mp_integer i=num_elements; i>0; --i)
112+
// byte extract will do the appropriate mapping, thus MSB comes
113+
// last here (as opposed to the above, where no further byte
114+
// extract is involved)
115+
for(mp_integer i=0; i<num_elements; ++i)
116116
{
117-
plus_exprt index(first_index, from_integer(i-1, offset_type));
117+
// the most significant byte comes first in the concatenation!
118+
plus_exprt index(first_index, from_integer(i, offset_type));
118119
concat.copy_to_operands(index_exprt(root, index));
119120
}
120121

121-
// the new offset is width%offset
122-
exprt new_offset;
123-
124-
if(element_width==1)
125-
new_offset=from_integer(0, offset_type);
126-
else
127-
new_offset=mod_exprt(offset, from_integer(element_width, offset_type));
122+
// the new offset is offset%width
123+
mod_exprt new_offset(offset,
124+
from_integer(element_width/8, offset_type));
128125

129126
// build new byte-extract expression
130-
exprt tmp(src.id(), src.type());
131-
tmp.copy_to_operands(concat, new_offset);
127+
byte_extract_exprt tmp(src);
128+
tmp.op()=concat;
129+
tmp.offset()=new_offset;
132130

133131
return tmp;
134132
}
@@ -166,7 +164,7 @@ exprt flatten_byte_extract(
166164

167165
extractbits.src()=left_shift;
168166
extractbits.type()=src.type();
169-
extractbits.upper()=from_integer(width_bits-1, offset_type);
167+
extractbits.upper()=from_integer(size_bits-1, offset_type);
170168
extractbits.lower()=from_integer(0, offset_type);
171169

172170
return extractbits;
@@ -186,11 +184,9 @@ Function: flatten_byte_update
186184
\*******************************************************************/
187185

188186
exprt flatten_byte_update(
189-
const exprt &src,
187+
const byte_update_exprt &src,
190188
const namespacet &ns)
191189
{
192-
assert(src.id()==ID_byte_update_little_endian ||
193-
src.id()==ID_byte_update_big_endian);
194190
assert(src.operands().size()==3);
195191

196192
mp_integer element_size=
@@ -233,7 +229,7 @@ exprt flatten_byte_update(
233229
}
234230
else
235231
{
236-
exprt byte_extract_expr(
232+
byte_extract_exprt byte_extract_expr(
237233
src.id()==ID_byte_update_little_endian?ID_byte_extract_little_endian:
238234
src.id()==ID_byte_update_big_endian?ID_byte_extract_big_endian:
239235
throw "unexpected src.id() in flatten_byte_update",
@@ -265,7 +261,7 @@ exprt flatten_byte_update(
265261

266262
index_exprt index_expr(src.op0(), div_offset, array_type.subtype());
267263

268-
exprt byte_update_expr(src.id(), array_type.subtype());
264+
byte_update_exprt byte_update_expr(src.id(), array_type.subtype());
269265
byte_update_expr.copy_to_operands(index_expr, mod_offset, src.op2());
270266

271267
// Call recurisvely, the array is gone!
@@ -380,10 +376,10 @@ exprt flatten_byte_operators(const exprt &src, const namespacet &ns)
380376

381377
if(src.id()==ID_byte_update_little_endian ||
382378
src.id()==ID_byte_update_big_endian)
383-
return flatten_byte_update(tmp, ns);
379+
return flatten_byte_update(to_byte_update_expr(tmp), ns);
384380
else if(src.id()==ID_byte_extract_little_endian ||
385381
src.id()==ID_byte_extract_big_endian)
386-
return flatten_byte_extract(tmp, ns);
382+
return flatten_byte_extract(to_byte_extract_expr(tmp), ns);
387383
else
388384
return tmp;
389385
}

src/solvers/flattening/flatten_byte_operators.h

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,17 @@ Author: Daniel Kroening, [email protected]
99
#ifndef CPROVER_FLATTEN_BYTE_OPERATORS_H
1010
#define CPROVER_FLATTEN_BYTE_OPERATORS_H
1111

12-
#include <util/expr.h>
13-
#include <util/namespace.h>
12+
class byte_extract_exprt;
13+
class byte_update_exprt;
14+
class exprt;
15+
class namespacet;
1416

15-
exprt flatten_byte_extract(const exprt &src, const namespacet &ns);
16-
exprt flatten_byte_update(const exprt &src, const namespacet &ns);
17+
exprt flatten_byte_extract(
18+
const byte_extract_exprt &src,
19+
const namespacet &ns);
20+
exprt flatten_byte_update(
21+
const byte_update_exprt &src,
22+
const namespacet &ns);
1723
exprt flatten_byte_operators(const exprt &src, const namespacet &ns);
1824
bool has_byte_operator(const exprt &src);
1925

src/solvers/smt1/smt1_conv.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ Author: Daniel Kroening, [email protected]
1717
#include <util/pointer_offset_size.h>
1818
#include <util/base_type.h>
1919
#include <util/ieee_float.h>
20+
#include <util/byte_operators.h>
2021

2122
#include <ansi-c/string_constant.h>
2223

@@ -470,7 +471,7 @@ Function: smt1_convt::convert_byte_extract
470471
\*******************************************************************/
471472

472473
void smt1_convt::convert_byte_extract(
473-
const exprt &expr,
474+
const byte_extract_exprt &expr,
474475
bool bool_as_bv)
475476
{
476477
// we just run the flattener
@@ -1183,7 +1184,7 @@ void smt1_convt::convert_expr(const exprt &expr, bool bool_as_bv)
11831184
else if(expr.id()==ID_byte_extract_little_endian ||
11841185
expr.id()==ID_byte_extract_big_endian)
11851186
{
1186-
convert_byte_extract(expr, bool_as_bv);
1187+
convert_byte_extract(to_byte_extract_expr(expr), bool_as_bv);
11871188
}
11881189
else if(expr.id()==ID_byte_update_little_endian ||
11891190
expr.id()==ID_byte_update_big_endian)

src/solvers/smt1/smt1_conv.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ Revision: Roberto Bruttomesso, [email protected]
2020
#include <solvers/flattening/pointer_logic.h>
2121
#include <solvers/flattening/boolbv_width.h>
2222

23+
class byte_extract_exprt;
2324
class typecast_exprt;
2425
class constant_exprt;
2526
class index_exprt;
@@ -77,7 +78,9 @@ class smt1_convt:public prop_convt
7778

7879
// specific expressions go here
7980
void convert_byte_update(const exprt &expr, bool bool_as_bv);
80-
void convert_byte_extract(const exprt &expr, bool bool_as_bv);
81+
void convert_byte_extract(
82+
const byte_extract_exprt &expr,
83+
bool bool_as_bv);
8184
void convert_typecast(const typecast_exprt &expr, bool bool_as_bv);
8285
void convert_struct(const exprt &expr);
8386
void convert_union(const exprt &expr);

src/util/byte_operators.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,12 @@ class byte_update_exprt:public exprt
127127
operands().resize(3);
128128
}
129129

130+
inline byte_update_exprt(irep_idt _id, const typet &_type):
131+
exprt(_id, _type)
132+
{
133+
operands().resize(3);
134+
}
135+
130136
inline byte_update_exprt(
131137
irep_idt _id,
132138
const exprt &_op, const exprt &_offset, const exprt &_value):

0 commit comments

Comments
 (0)