1 | // RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify -analyzer-config eagerly-assume=false %s |
2 | |
3 | void clang_analyzer_eval(bool); |
4 | |
5 | void usePointer(int * const *); |
6 | void useReference(int * const &); |
7 | |
8 | void testPointer() { |
9 | int x; |
10 | int *p; |
11 | |
12 | p = &x; |
13 | x = 42; |
14 | clang_analyzer_eval(x == 42); // expected-warning{{TRUE}} |
15 | usePointer(&p); |
16 | clang_analyzer_eval(x == 42); // expected-warning{{UNKNOWN}} |
17 | |
18 | p = &x; |
19 | x = 42; |
20 | clang_analyzer_eval(x == 42); // expected-warning{{TRUE}} |
21 | useReference(p); |
22 | clang_analyzer_eval(x == 42); // expected-warning{{UNKNOWN}} |
23 | |
24 | int * const cp1 = &x; |
25 | x = 42; |
26 | clang_analyzer_eval(x == 42); // expected-warning{{TRUE}} |
27 | usePointer(&cp1); |
28 | clang_analyzer_eval(x == 42); // expected-warning{{UNKNOWN}} |
29 | |
30 | int * const cp2 = &x; |
31 | x = 42; |
32 | clang_analyzer_eval(x == 42); // expected-warning{{TRUE}} |
33 | useReference(cp2); |
34 | clang_analyzer_eval(x == 42); // expected-warning{{UNKNOWN}} |
35 | } |
36 | |
37 | |
38 | struct Wrapper { |
39 | int *ptr; |
40 | }; |
41 | |
42 | void useStruct(Wrapper &w); |
43 | void useConstStruct(const Wrapper &w); |
44 | |
45 | void testPointerStruct() { |
46 | int x; |
47 | Wrapper w; |
48 | |
49 | w.ptr = &x; |
50 | x = 42; |
51 | clang_analyzer_eval(x == 42); // expected-warning{{TRUE}} |
52 | useStruct(w); |
53 | clang_analyzer_eval(x == 42); // expected-warning{{UNKNOWN}} |
54 | |
55 | w.ptr = &x; |
56 | x = 42; |
57 | clang_analyzer_eval(x == 42); // expected-warning{{TRUE}} |
58 | useConstStruct(w); |
59 | clang_analyzer_eval(x == 42); // expected-warning{{UNKNOWN}} |
60 | } |
61 | |
62 | |
63 | struct RefWrapper { |
64 | int &ref; |
65 | }; |
66 | |
67 | void useStruct(RefWrapper &w); |
68 | void useConstStruct(const RefWrapper &w); |
69 | |
70 | void testReferenceStruct() { |
71 | int x; |
72 | RefWrapper w = { x }; |
73 | |
74 | x = 42; |
75 | clang_analyzer_eval(x == 42); // expected-warning{{TRUE}} |
76 | useStruct(w); |
77 | clang_analyzer_eval(x == 42); // expected-warning{{UNKNOWN}} |
78 | } |
79 | |
80 | // FIXME: This test is split into two functions because region invalidation |
81 | // does not preserve reference bindings. <rdar://problem/13320347> |
82 | void testConstReferenceStruct() { |
83 | int x; |
84 | RefWrapper w = { x }; |
85 | |
86 | x = 42; |
87 | clang_analyzer_eval(x == 42); // expected-warning{{TRUE}} |
88 | useConstStruct(w); |
89 | clang_analyzer_eval(x == 42); // expected-warning{{UNKNOWN}} |
90 | } |
91 | |
92 | |
93 | void usePointerPure(int * const *) __attribute__((pure)); |
94 | void usePointerConst(int * const *) __attribute__((const)); |
95 | |
96 | void testPureConst() { |
97 | extern int global; |
98 | int x; |
99 | int *p; |
100 | |
101 | p = &x; |
102 | x = 42; |
103 | global = -5; |
104 | clang_analyzer_eval(x == 42); // expected-warning{{TRUE}} |
105 | clang_analyzer_eval(global == -5); // expected-warning{{TRUE}} |
106 | |
107 | usePointerPure(&p); |
108 | clang_analyzer_eval(x == 42); // expected-warning{{TRUE}} |
109 | clang_analyzer_eval(global == -5); // expected-warning{{TRUE}} |
110 | |
111 | usePointerConst(&p); |
112 | clang_analyzer_eval(x == 42); // expected-warning{{TRUE}} |
113 | clang_analyzer_eval(global == -5); // expected-warning{{TRUE}} |
114 | |
115 | usePointer(&p); |
116 | clang_analyzer_eval(x == 42); // expected-warning{{UNKNOWN}} |
117 | clang_analyzer_eval(global == -5); // expected-warning{{UNKNOWN}} |
118 | } |
119 | |
120 | |
121 | struct PlainStruct { |
122 | int x, y; |
123 | mutable int z; |
124 | }; |
125 | |
126 | PlainStruct glob; |
127 | |
128 | void useAnything(void *); |
129 | void useAnythingConst(const void *); |
130 | |
131 | void testInvalidationThroughBaseRegionPointer() { |
132 | PlainStruct s1; |
133 | s1.x = 1; |
134 | s1.z = 1; |
135 | s1.y = 1; |
136 | clang_analyzer_eval(s1.x == 1); // expected-warning{{TRUE}} |
137 | clang_analyzer_eval(s1.z == 1); // expected-warning{{TRUE}} |
138 | // Not only passing a structure pointer through const pointer parameter, |
139 | // but also passing a field pointer through const pointer parameter |
140 | // should preserve the contents of the structure. |
141 | useAnythingConst(&(s1.y)); |
142 | clang_analyzer_eval(s1.y == 1); // expected-warning{{TRUE}} |
143 | clang_analyzer_eval(s1.x == 1); // expected-warning{{TRUE}} |
144 | // FIXME: Should say "UNKNOWN", because it is not uncommon to |
145 | // modify a mutable member variable through const pointer. |
146 | clang_analyzer_eval(s1.z == 1); // expected-warning{{TRUE}} |
147 | useAnything(&(s1.y)); |
148 | clang_analyzer_eval(s1.x == 1); // expected-warning{{TRUE}} |
149 | clang_analyzer_eval(s1.y == 1); // expected-warning{{UNKNOWN}} |
150 | } |
151 | |
152 | |
153 | void useFirstConstSecondNonConst(const void *x, void *y); |
154 | void useFirstNonConstSecondConst(void *x, const void *y); |
155 | |
156 | void testMixedConstNonConstCalls() { |
157 | PlainStruct s2; |
158 | s2.x = 1; |
159 | useFirstConstSecondNonConst(&(s2.x), &(s2.y)); |
160 | clang_analyzer_eval(s2.x == 1); // expected-warning{{UNKNOWN}} |
161 | s2.x = 1; |
162 | useFirstNonConstSecondConst(&(s2.x), &(s2.y)); |
163 | clang_analyzer_eval(s2.x == 1); // expected-warning{{UNKNOWN}} |
164 | s2.y = 1; |
165 | useFirstConstSecondNonConst(&(s2.x), &(s2.y)); |
166 | clang_analyzer_eval(s2.y == 1); // expected-warning{{UNKNOWN}} |
167 | s2.y = 1; |
168 | useFirstNonConstSecondConst(&(s2.x), &(s2.y)); |
169 | clang_analyzer_eval(s2.y == 1); // expected-warning{{UNKNOWN}} |
170 | } |
171 | |