Skip to content

Commit cf187c8

Browse files
authored
Merge pull request #1654 from NlightNFotis/fotis/pb10_develop
Fix for the handling of constant arrays and members of structs being marked nondet.
2 parents a61ea38 + b5faf52 commit cf187c8

File tree

5 files changed

+217
-2
lines changed

5 files changed

+217
-2
lines changed
+100
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
#define NULL 0
2+
3+
int x;
4+
int y = 23;
5+
const int z = 23;
6+
const int array[] = { 5, 6, 7, 8};
7+
8+
struct s { int x; };
9+
struct s s1;
10+
struct s s2 = { 23 };
11+
const struct s s3 = { 23 };
12+
13+
struct t { int x; const int y; };
14+
struct t t1;
15+
struct t t2 = { 23, 23 };
16+
const struct t t3 = { 23, 23 };
17+
18+
struct u { const int x; };
19+
struct u u1;
20+
struct u u2 = { 23 };
21+
const struct u u3 = { 23 };
22+
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+
37+
struct contains_pointer { int x; int *p; };
38+
// const int *p : declare p as pointer to const int
39+
struct contains_pointer_to_const { int x; const int *p; };
40+
// int * const p : declare p as const pointer to int
41+
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; };
44+
45+
struct contains_pointer a[3] = { {23, &x}, {23, &x}, {23, &x} };
46+
struct contains_constant_pointer b[3] = { {23, &y}, {23, &y}, {23, &y} };
47+
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};
53+
54+
typedef int Int;
55+
typedef const int Const_Int;
56+
57+
const Int p = 23;
58+
Const_Int q = 23;
59+
60+
61+
#include <assert.h>
62+
63+
int main (int argc, char **argv)
64+
{
65+
struct list linked_list = {5, &node};
66+
67+
/* Pass normally but fail with nondet-static */
68+
assert(x == 0);
69+
assert(y == 23);
70+
assert(s1.x == 0);
71+
assert(s2.x == 23);
72+
assert(a[0].x == 23);
73+
assert(a[0].p == &x);
74+
assert(c[2].x == 23);
75+
assert(c[2].p == &z);
76+
77+
/* Should still pass */
78+
assert(z == 23);
79+
assert(s3.x == 23);
80+
assert(t1.y == 0);
81+
assert(t2.y == 23);
82+
assert(t3.x == 23);
83+
assert(t3.y == 23);
84+
assert(u1.x == 0);
85+
assert(u2.x == 23);
86+
assert(u3.x == 23);
87+
assert(p == 23);
88+
assert(q == 23);
89+
assert(t1.x == 0);
90+
assert(t2.x == 23);
91+
assert(b[1].x == 23);
92+
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);
98+
99+
return 0;
100+
}
+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
CORE
2+
main.c
3+
--nondet-static
4+
^VERIFICATION FAILED$
5+
^EXIT=10$
6+
^SIGNAL=0$
7+
assertion x == 0: FAILURE
8+
assertion y == 23: FAILURE
9+
assertion s1.x == 0: FAILURE
10+
assertion s2.x == 23: FAILURE
11+
assertion a\[0\].x == 23: FAILURE
12+
assertion a\[0\].p == &x: FAILURE
13+
assertion c\[2\].x == 23: FAILURE
14+
assertion c\[2\].p == &z: FAILURE
15+
assertion z == 23: SUCCESS
16+
assertion s3.x == 23: SUCCESS
17+
assertion t1.y == 0: SUCCESS
18+
assertion t2.y == 23: SUCCESS
19+
assertion t3.x == 23: SUCCESS
20+
assertion t3.y == 23: SUCCESS
21+
assertion u1.x == 0: SUCCESS
22+
assertion u2.x == 23: SUCCESS
23+
assertion u3.x == 23: SUCCESS
24+
assertion p == 23: SUCCESS
25+
assertion q == 23: SUCCESS
26+
assertion t1.x == 0: SUCCESS
27+
assertion t2.x == 23: SUCCESS
28+
assertion b\[1\].x == 23: SUCCESS
29+
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
35+
--
36+
--

src/goto-instrument/nondet_static.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ void nondet_static(
5151
continue;
5252

5353
// constant?
54-
if(sym.type().get_bool(ID_C_constant))
54+
if(is_constant_or_has_constant_components(sym.type(), ns))
5555
continue;
5656

5757
i_it=init.insert_before(++i_it);

src/util/type.cpp

+73-1
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ Author: Daniel Kroening, [email protected]
66
77
\*******************************************************************/
88

9-
109
#include "type.h"
10+
#include "std_types.h"
11+
#include "namespace.h"
1112

1213
void typet::copy_to_subtypes(const typet &type)
1314
{
@@ -34,3 +35,74 @@ bool is_number(const typet &type)
3435
id==ID_floatbv ||
3536
id==ID_fixedbv;
3637
}
38+
39+
/// Identify if a given type is constant itself or
40+
/// contains constant components. Examples include:
41+
/// - const int a;
42+
/// - struct contains_constant_pointer { int x; int * const p; };
43+
/// - const int b[3];
44+
/// \param type The type we want to query constness of.
45+
/// \param ns The namespace, needed for resolution of symbols.
46+
/// \return Whether passed in type is const or not.
47+
bool is_constant_or_has_constant_components(
48+
const typet &type, const namespacet &ns)
49+
{
50+
// Helper function to avoid the code duplication in the branches
51+
// below.
52+
const auto has_constant_components =
53+
[&ns](const typet &subtype) -> bool
54+
{
55+
if(subtype.id() == ID_struct || subtype.id() == ID_union)
56+
{
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+
}
63+
}
64+
return false;
65+
};
66+
67+
// There are 4 possibilities the code below is handling.
68+
// The possibilities are enumerated as comments, to show
69+
// what each code is supposed to be handling. For more
70+
// comprehensive test case for this, take a look at
71+
// regression/cbmc/no_nondet_static/main.c
72+
73+
// const int a;
74+
if(type.get_bool(ID_C_constant))
75+
return true;
76+
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+
85+
// When we have a case like the following, we don't immediately
86+
// see the struct t. Instead, we only get to see symbol t1, which
87+
// we have to use the namespace to resolve to its definition:
88+
// struct t { const int a; };
89+
// struct t t1;
90+
if(type.id() == ID_symbol)
91+
{
92+
const auto &resolved_type = ns.follow(type);
93+
return has_constant_components(resolved_type);
94+
}
95+
96+
// In a case like this, where we see an array (b[3] here), we know that
97+
// the array contains subtypes. We get the first one, and
98+
// then resolve it to its definition through the usage of the namespace.
99+
// struct contains_constant_pointer { int x; int * const p; };
100+
// struct contains_constant_pointer b[3] = { {23, &y}, {23, &y}, {23, &y} };
101+
if(type.has_subtype())
102+
{
103+
const auto &subtype = type.subtype();
104+
return is_constant_or_has_constant_components(subtype, ns);
105+
}
106+
107+
return false;
108+
}

src/util/type.h

+7
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ Author: Daniel Kroening, [email protected]
1515
#define SUBTYPE_IN_GETSUB
1616
#define SUBTYPES_IN_GETSUB
1717

18+
class namespacet;
19+
1820
/*! \brief The type of an expression
1921
*/
2022
class typet:public irept
@@ -203,4 +205,9 @@ pre-defined types:
203205
bool is_number(const typet &type);
204206
// rational, real, integer, complex, unsignedbv, signedbv, floatbv
205207

208+
// Is the passed in type const qualified?
209+
bool is_constant_or_has_constant_components(
210+
const typet &type,
211+
const namespacet &ns);
212+
206213
#endif // CPROVER_UTIL_TYPE_H

0 commit comments

Comments
 (0)