Skip to content

Commit cd60782

Browse files
committed
Fix for the constant arrays marked as nondet issue.
1 parent 04766b2 commit cd60782

File tree

5 files changed

+177
-1
lines changed

5 files changed

+177
-1
lines changed
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
int x;
2+
int y = 23;
3+
const int z = 23;
4+
5+
struct s { int x; };
6+
struct s s1;
7+
struct s s2 = { 23 };
8+
const struct s s3 = { 23 };
9+
10+
struct t { int x; const int y; };
11+
struct t t1;
12+
struct t t2 = { 23, 23 };
13+
const struct t t3 = { 23, 23 };
14+
15+
struct u { const int x; };
16+
struct u u1;
17+
struct u u2 = { 23 };
18+
const struct u u3 = { 23 };
19+
20+
struct contains_pointer { int x; int *p; };
21+
// const int *p : declare p as pointer to const int
22+
struct contains_pointer_to_const { int x; const int *p; };
23+
// int * const p : declare p as const pointer to int
24+
struct contains_constant_pointer { int x; int * const p; };
25+
26+
struct contains_pointer a[3] = { {23, &x}, {23, &x}, {23, &x} };
27+
struct contains_constant_pointer b[3] = { {23, &y}, {23, &y}, {23, &y} };
28+
struct contains_pointer_to_const c[3] = { {23, &z}, {23, &z}, {23, &z} };
29+
30+
typedef int Int;
31+
typedef const int Const_Int;
32+
33+
const Int p = 23;
34+
Const_Int q = 23;
35+
36+
37+
#include <assert.h>
38+
39+
int main (int argc, char **argv)
40+
{
41+
/* Pass normally but fail with nondet-static */
42+
assert(x == 0);
43+
assert(y == 23);
44+
assert(s1.x == 0);
45+
assert(s2.x == 23);
46+
assert(a[0].x == 23);
47+
assert(a[0].p == &x);
48+
assert(c[2].x == 23);
49+
assert(c[2].p == &z);
50+
51+
/* Should still pass */
52+
assert(z == 23);
53+
assert(s3.x == 23);
54+
assert(t1.y == 0);
55+
assert(t2.y == 23);
56+
assert(t3.x == 23);
57+
assert(t3.y == 23);
58+
assert(u1.x == 0);
59+
assert(u2.x == 23);
60+
assert(u3.x == 23);
61+
assert(p == 23);
62+
assert(q == 23);
63+
assert(t1.x == 0);
64+
assert(t2.x == 23);
65+
assert(b[1].x == 23);
66+
assert(b[1].p == &y);
67+
68+
return 0;
69+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
CORE
2+
main.c
3+
--nondet-static
4+
^VERIFICATION FAILED$
5+
assertion x == 0: FAILURE
6+
assertion y == 23: FAILURE
7+
assertion s1.x == 0: FAILURE
8+
assertion s2.x == 23: FAILURE
9+
assertion a\[0\].x == 23: FAILURE
10+
assertion a\[0\].p == &x: FAILURE
11+
assertion c\[2\].x == 23: FAILURE
12+
assertion c\[2\].p == &z: FAILURE
13+
assertion z == 23: SUCCESS
14+
assertion s3.x == 23: SUCCESS
15+
assertion t1.y == 0: SUCCESS
16+
assertion t2.y == 23: SUCCESS
17+
assertion t3.x == 23: SUCCESS
18+
assertion t3.y == 23: SUCCESS
19+
assertion u1.x == 0: SUCCESS
20+
assertion u2.x == 23: SUCCESS
21+
assertion u3.x == 23: SUCCESS
22+
assertion p == 23: SUCCESS
23+
assertion q == 23: SUCCESS
24+
assertion t1.x == 0: SUCCESS
25+
assertion t2.x == 23: SUCCESS
26+
assertion b\[1\].x == 23: SUCCESS
27+
assertion b\[1\].p == &y: SUCCESS
28+
--
29+
--

src/goto-instrument/nondet_static.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ 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>
2122

2223
#include <goto-programs/goto_model.h>
2324
#include <goto-programs/goto_functions.h>
@@ -51,7 +52,7 @@ void nondet_static(
5152
continue;
5253

5354
// constant?
54-
if(sym.type().get_bool(ID_C_constant))
55+
if(is_constant_or_has_constant_components(sym.type(), ns))
5556
continue;
5657

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

src/util/type.cpp

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ Author: Daniel Kroening, [email protected]
88

99

1010
#include "type.h"
11+
#include "std_types.h"
12+
#include "namespace.h"
1113

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

src/util/type.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ Author: Daniel Kroening, [email protected]
1111
#define CPROVER_UTIL_TYPE_H
1212

1313
#include <util/source_location.h>
14+
#include "namespace.h"
1415

1516
#define SUBTYPE_IN_GETSUB
1617
#define SUBTYPES_IN_GETSUB
@@ -203,4 +204,9 @@ pre-defined types:
203204
bool is_number(const typet &type);
204205
// rational, real, integer, complex, unsignedbv, signedbv, floatbv
205206

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

0 commit comments

Comments
 (0)