Skip to content

Commit b9d06a1

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.
1 parent de5fe0f commit b9d06a1

File tree

4 files changed

+106
-5
lines changed

4 files changed

+106
-5
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 (int) + 2 * 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

src/solvers/flattening/boolbv_byte_extract.cpp

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ Author: Daniel Kroening, [email protected]
1313
#include <util/arith_tools.h>
1414
#include <util/byte_operators.h>
1515
#include <util/endianness_map.h>
16+
#include <util/pointer_offset_size.h>
1617
#include <util/std_expr.h>
1718
#include <util/throw_with_nested.h>
1819

@@ -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: 24 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,28 @@ 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 =
349+
simplify_expr(
350+
plus_exprt(
351+
o.offset(),
352+
from_integer(index * subtype_bytes, o.offset().type())), ns);
353+
354+
byte_extract_exprt be(
355+
byte_extract_id(), o.root_object(), new_offset, array_type.subtype());
356+
357+
return convert_bv(be);
358+
}
336359
else
337360
{
338361
// out of bounds

0 commit comments

Comments
 (0)