Skip to content

Commit b5faf52

Browse files
committed
Fix the handling of recursive data types.
1 parent cd60782 commit b5faf52

File tree

5 files changed

+66
-27
lines changed

5 files changed

+66
-27
lines changed

regression/cbmc/no_nondet_static/main.c

+32-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1+
#define NULL 0
2+
13
int x;
24
int y = 23;
35
const int z = 23;
6+
const int array[] = { 5, 6, 7, 8};
47

58
struct s { int x; };
69
struct s s1;
@@ -17,15 +20,36 @@ struct u u1;
1720
struct u u2 = { 23 };
1821
const struct u u3 = { 23 };
1922

23+
struct list { const int datum; struct list * next; };
24+
25+
// The point of this is that cbmc needs to correctly handle
26+
// the embedded datum int the nested struct which is const,
27+
// while not falling into infinite recursion from the
28+
// recursive field.
29+
struct another_list {
30+
struct a_list {
31+
struct a_list * next;
32+
const int datum;
33+
} embedded;
34+
int a;
35+
};
36+
2037
struct contains_pointer { int x; int *p; };
2138
// const int *p : declare p as pointer to const int
2239
struct contains_pointer_to_const { int x; const int *p; };
2340
// int * const p : declare p as const pointer to int
2441
struct contains_constant_pointer { int x; int * const p; };
42+
// this should cause a bug
43+
struct contains_pointer_to_const_point { int x; int * y; int * const p; };
2544

2645
struct contains_pointer a[3] = { {23, &x}, {23, &x}, {23, &x} };
2746
struct contains_constant_pointer b[3] = { {23, &y}, {23, &y}, {23, &y} };
2847
struct contains_pointer_to_const c[3] = { {23, &z}, {23, &z}, {23, &z} };
48+
struct contains_pointer_to_const_point d[3]= { {23, &y, &z}, {23, &y, &z}, {23, &y, &z} };
49+
50+
struct list node = {10, NULL};
51+
52+
struct another_list one_list = {{10, NULL}, 5};
2953

3054
typedef int Int;
3155
typedef const int Const_Int;
@@ -37,7 +61,9 @@ Const_Int q = 23;
3761
#include <assert.h>
3862

3963
int main (int argc, char **argv)
40-
{
64+
{
65+
struct list linked_list = {5, &node};
66+
4167
/* Pass normally but fail with nondet-static */
4268
assert(x == 0);
4369
assert(y == 23);
@@ -64,6 +90,11 @@ int main (int argc, char **argv)
6490
assert(t2.x == 23);
6591
assert(b[1].x == 23);
6692
assert(b[1].p == &y);
93+
assert(d[1].y == &y);
94+
assert(linked_list.datum == 5);
95+
assert(linked_list.next->datum == 10);
96+
assert(one_list.a == 5);
97+
assert(array[1] == 6);
6798

6899
return 0;
69100
}

regression/cbmc/no_nondet_static/test.desc

+7
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ CORE
22
main.c
33
--nondet-static
44
^VERIFICATION FAILED$
5+
^EXIT=10$
6+
^SIGNAL=0$
57
assertion x == 0: FAILURE
68
assertion y == 23: FAILURE
79
assertion s1.x == 0: FAILURE
@@ -25,5 +27,10 @@ assertion t1.x == 0: SUCCESS
2527
assertion t2.x == 23: SUCCESS
2628
assertion b\[1\].x == 23: SUCCESS
2729
assertion b\[1\].p == &y: SUCCESS
30+
assertion d\[1\].y == &y: SUCCESS
31+
assertion linked_list.datum == 5: SUCCESS
32+
assertion linked_list.next->datum == 10: SUCCESS
33+
assertion one_list.a == 5: SUCCESS
34+
assertion array\[1\] == 6: SUCCESS
2835
--
2936
--

src/goto-instrument/nondet_static.cpp

-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ Date: November 2011
1818
#include <util/std_expr.h>
1919
#include <util/cprover_prefix.h>
2020
#include <util/prefix.h>
21-
#include <util/type.h>
2221

2322
#include <goto-programs/goto_model.h>
2423
#include <goto-programs/goto_functions.h>

src/util/type.cpp

+25-24
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ Author: Daniel Kroening, [email protected]
66
77
\*******************************************************************/
88

9-
109
#include "type.h"
1110
#include "std_types.h"
1211
#include "namespace.h"
@@ -48,26 +47,24 @@ bool is_number(const typet &type)
4847
bool is_constant_or_has_constant_components(
4948
const typet &type, const namespacet &ns)
5049
{
51-
// Helper function to avoid the code duplication
52-
// in the branches below.
50+
// Helper function to avoid the code duplication in the branches
51+
// below.
5352
const auto has_constant_components =
54-
[](const typet &subtype) -> bool
55-
{
56-
if(subtype.id() == ID_struct || subtype.id() == ID_union)
53+
[&ns](const typet &subtype) -> bool
5754
{
58-
const auto &struct_union_type = to_struct_union_type(subtype);
59-
for(const auto &component : struct_union_type.components())
55+
if(subtype.id() == ID_struct || subtype.id() == ID_union)
6056
{
61-
if(component.type().id() == ID_pointer)
62-
return component.type().get_bool(ID_C_constant);
63-
if(component.type().get_bool(ID_C_constant))
64-
return true;
57+
const auto &struct_union_type = to_struct_union_type(subtype);
58+
for(const auto &component : struct_union_type.components())
59+
{
60+
if(is_constant_or_has_constant_components(component.type(), ns))
61+
return true;
62+
}
6563
}
66-
}
67-
return false;
68-
};
64+
return false;
65+
};
6966

70-
// There are 3 possibilities the code below is handling.
67+
// There are 4 possibilities the code below is handling.
7168
// The possibilities are enumerated as comments, to show
7269
// what each code is supposed to be handling. For more
7370
// comprehensive test case for this, take a look at
@@ -77,30 +74,34 @@ bool is_constant_or_has_constant_components(
7774
if(type.get_bool(ID_C_constant))
7875
return true;
7976

77+
// This is a termination condition to break the recursion
78+
// for recursive types such as the following:
79+
// struct list { const int datum; struct list * next; };
80+
// NOTE: the difference between this condition and the previous
81+
// one is that this one always returns.
82+
if(type.id()==ID_pointer)
83+
return type.get_bool(ID_C_constant);
84+
8085
// When we have a case like the following, we don't immediately
8186
// see the struct t. Instead, we only get to see symbol t1, which
8287
// we have to use the namespace to resolve to its definition:
8388
// struct t { const int a; };
8489
// struct t t1;
8590
if(type.id() == ID_symbol)
8691
{
87-
const auto &subtype = ns.follow(type);
88-
return has_constant_components(subtype);
92+
const auto &resolved_type = ns.follow(type);
93+
return has_constant_components(resolved_type);
8994
}
9095

91-
// In a case like this, were we see an array (b[3] here), we know that
96+
// In a case like this, where we see an array (b[3] here), we know that
9297
// the array contains subtypes. We get the first one, and
9398
// then resolve it to its definition through the usage of the namespace.
9499
// struct contains_constant_pointer { int x; int * const p; };
95100
// struct contains_constant_pointer b[3] = { {23, &y}, {23, &y}, {23, &y} };
96101
if(type.has_subtype())
97102
{
98103
const auto &subtype = type.subtype();
99-
if(subtype.id() == ID_symbol)
100-
{
101-
const auto &new_subtype = ns.follow(to_symbol_type(subtype));
102-
return has_constant_components(new_subtype);
103-
}
104+
return is_constant_or_has_constant_components(subtype, ns);
104105
}
105106

106107
return false;

src/util/type.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,12 @@ Author: Daniel Kroening, [email protected]
1111
#define CPROVER_UTIL_TYPE_H
1212

1313
#include <util/source_location.h>
14-
#include "namespace.h"
1514

1615
#define SUBTYPE_IN_GETSUB
1716
#define SUBTYPES_IN_GETSUB
1817

18+
class namespacet;
19+
1920
/*! \brief The type of an expression
2021
*/
2122
class typet:public irept

0 commit comments

Comments
 (0)