Skip to content

Commit 6111fd1

Browse files
committed
Fix flattening of access beyond type-specified bounds
The test Pointer_byte_extract5 was previously only solved properly thanks to hacks in the simplifier. We should not have to rely on those. Also adjust the malloc size computation to not rely on absence of padding.
1 parent 8412eb0 commit 6111fd1

File tree

5 files changed

+106
-6
lines changed

5 files changed

+106
-6
lines changed
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
void *malloc(__CPROVER_size_t);
2+
3+
typedef union
4+
{
5+
int a;
6+
int b;
7+
} Union;
8+
9+
#ifdef __GNUC__
10+
typedef struct
11+
{
12+
int Count;
13+
Union List[1];
14+
} __attribute__((packed)) Struct3;
15+
#else
16+
typedef struct
17+
{
18+
int Count;
19+
Union List[1];
20+
} Struct3;
21+
#endif
22+
23+
int main()
24+
{
25+
Struct3 *p = malloc(sizeof(Struct3) + sizeof(Union));
26+
p->Count = 3;
27+
int po = 0;
28+
29+
// this should be fine
30+
p->List[0].a = 555;
31+
32+
__CPROVER_assert(p->List[0].b == 555, "p->List[0].b==555");
33+
__CPROVER_assert(p->List[0].a == 555, "p->List[0].a==555");
34+
35+
// this should be fine
36+
p->List[1].b = 999;
37+
38+
__CPROVER_assert(p->List[1].b == 999, "p->List[1].b==999");
39+
__CPROVER_assert(p->List[1].a == 999, "p->List[1].a==999");
40+
41+
// this is out-of-bounds
42+
p->List[2].a = 0;
43+
44+
return 0;
45+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
CORE
2+
main.c
3+
--bounds-check --32 --no-simplify
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
array\.List dynamic object upper bound in p->List\[2\]: FAILURE
7+
\*\* 1 of 14 failed
8+
--
9+
^warning: ignoring

regression/cbmc/Pointer_byte_extract5/main.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ typedef struct
2222

2323
int main()
2424
{
25-
Struct3 *p = malloc (sizeof (int) + 2 * sizeof(Union));
25+
Struct3 *p = malloc(sizeof(Struct3) + sizeof(Union));
2626
p->Count = 3;
2727
int po=0;
2828

src/solvers/flattening/boolbv_byte_extract.cpp

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Author: Daniel Kroening, [email protected]
1212

1313
#include <util/arith_tools.h>
1414
#include <util/byte_operators.h>
15+
#include <util/pointer_offset_size.h>
1516
#include <util/std_expr.h>
1617
#include <util/throw_with_nested.h>
1718

@@ -78,6 +79,30 @@ bvt boolbvt::convert_byte_extract(const byte_extract_exprt &expr)
7879
if(width==0)
7980
return conversion_failed(expr);
8081

82+
// see if the byte number is constant and within bounds, else work from the
83+
// root object
84+
const mp_integer op_bytes = pointer_offset_size(expr.op().type(), ns);
85+
auto index = numeric_cast<mp_integer>(expr.offset());
86+
if(
87+
(!index.has_value() || (*index < 0 || *index >= op_bytes)) &&
88+
(expr.op().id() == ID_member || expr.op().id() == ID_index ||
89+
expr.op().id() == ID_byte_extract_big_endian ||
90+
expr.op().id() == ID_byte_extract_little_endian))
91+
{
92+
object_descriptor_exprt o;
93+
o.build(expr.op(), ns);
94+
CHECK_RETURN(o.offset().id() != ID_unknown);
95+
if(o.offset().type() != expr.offset().type())
96+
o.offset().make_typecast(expr.offset().type());
97+
byte_extract_exprt be(
98+
expr.id(),
99+
o.root_object(),
100+
plus_exprt(o.offset(), expr.offset()),
101+
expr.type());
102+
103+
return convert_bv(be);
104+
}
105+
81106
const exprt &op=expr.op();
82107
const exprt &offset=expr.offset();
83108

@@ -106,13 +131,12 @@ bvt boolbvt::convert_byte_extract(const byte_extract_exprt &expr)
106131
// see if the byte number is constant
107132
unsigned byte_width=8;
108133

109-
mp_integer index;
110-
if(!to_integer(offset, index))
134+
if(index.has_value())
111135
{
112-
if(index<0)
136+
if(*index < 0)
113137
throw "byte_extract flatting with negative offset: "+expr.pretty();
114138

115-
mp_integer offset=index*byte_width;
139+
const mp_integer offset = *index * byte_width;
116140

117141
std::size_t offset_i=integer2unsigned(offset);
118142

src/solvers/flattening/boolbv_index.cpp

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@ Author: Daniel Kroening, [email protected]
1111
#include <cassert>
1212

1313
#include <util/arith_tools.h>
14-
#include <util/std_expr.h>
14+
#include <util/pointer_offset_size.h>
1515
#include <util/simplify_expr.h>
16+
#include <util/std_expr.h>
1617

1718
bvt boolbvt::convert_index(const index_exprt &expr)
1819
{
@@ -333,6 +334,27 @@ bvt boolbvt::convert_index(
333334
for(std::size_t i=0; i<width; i++)
334335
bv[i]=tmp[integer2size_t(offset+i)];
335336
}
337+
else if(
338+
array.id() == ID_member || array.id() == ID_index ||
339+
array.id() == ID_byte_extract_big_endian ||
340+
array.id() == ID_byte_extract_little_endian)
341+
{
342+
object_descriptor_exprt o;
343+
o.build(array, ns);
344+
CHECK_RETURN(o.offset().id() != ID_unknown);
345+
346+
const mp_integer subtype_bytes =
347+
pointer_offset_size(array_type.subtype(), ns);
348+
exprt new_offset = simplify_expr(
349+
plus_exprt(
350+
o.offset(), from_integer(index * subtype_bytes, o.offset().type())),
351+
ns);
352+
353+
byte_extract_exprt be(
354+
byte_extract_id(), o.root_object(), new_offset, array_type.subtype());
355+
356+
return convert_bv(be);
357+
}
336358
else
337359
{
338360
// out of bounds

0 commit comments

Comments
 (0)