1 | // RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-config suppress-inlined-defensive-checks=true -verify %s |
2 | |
3 | // Perform inline defensive checks. |
4 | void idc(void *p) { |
5 | if (p) |
6 | ; |
7 | } |
8 | |
9 | int test01(int *p) { |
10 | if (p) |
11 | ; |
12 | return *p; // expected-warning {{Dereference of null pointer}} |
13 | } |
14 | |
15 | int test02(int *p, int *x) { |
16 | if (p) |
17 | ; |
18 | idc(p); |
19 | if (x) |
20 | ; |
21 | return *p; // expected-warning {{Dereference of null pointer}} |
22 | } |
23 | |
24 | int test03(int *p, int *x) { |
25 | idc(p); |
26 | if (p) |
27 | ; |
28 | return *p; // False negative |
29 | } |
30 | |
31 | int deref04(int *p) { |
32 | return *p; // expected-warning {{Dereference of null pointer}} |
33 | } |
34 | |
35 | int test04(int *p) { |
36 | if (p) |
37 | ; |
38 | idc(p); |
39 | return deref04(p); |
40 | } |
41 | |
42 | int test11(int *q, int *x) { |
43 | int *p = q; |
44 | if (q) |
45 | ; |
46 | if (x) |
47 | ; |
48 | return *p; // expected-warning{{Dereference of null pointer}} |
49 | } |
50 | |
51 | int test12(int *q) { |
52 | int *p = q; |
53 | idc(q); |
54 | return *p; |
55 | } |
56 | |
57 | int test13(int *q) { |
58 | int *p = q; |
59 | idc(p); |
60 | return *p; |
61 | } |
62 | |
63 | int test21(int *q, int *x) { |
64 | if (q) |
65 | ; |
66 | if (x) |
67 | ; |
68 | int *p = q; |
69 | return *p; // expected-warning{{Dereference of null pointer}} |
70 | } |
71 | |
72 | int test22(int *q, int *x) { |
73 | idc(q); |
74 | if (x) |
75 | ; |
76 | int *p = q; |
77 | return *p; |
78 | } |
79 | |
80 | int test23(int *q, int *x) { |
81 | idc(q); |
82 | if (x) |
83 | ; |
84 | int *p = q; |
85 | if (!p) |
86 | ; |
87 | return *p; // False negative |
88 | } |
89 | |
90 | void use(char *p) { |
91 | if (!p) |
92 | return; |
93 | p[0] = 'a'; |
94 | } |
95 | |
96 | void test24(char *buffer) { |
97 | use(buffer); |
98 | buffer[1] = 'b'; |
99 | } |
100 | |
101 | // Ensure idc works on pointers with constant offset. |
102 | void idcchar(const char *s2) { |
103 | if(s2) |
104 | ; |
105 | } |
106 | void testConstantOffset(char *value) { |
107 | char *cursor = value + 5; |
108 | idcchar(cursor); |
109 | if (*cursor) { |
110 | cursor++; |
111 | } |
112 | } |
113 | |
114 | // Ensure idc works for integer zero values (ex: suppressed div by zero). |
115 | void idcZero(int assume) { |
116 | if (assume) |
117 | ; |
118 | } |
119 | |
120 | int idcTriggerZeroValue(int m) { |
121 | idcZero(m); |
122 | return 5/m; // no-warning |
123 | } |
124 | |
125 | int idcTriggerZeroValueThroughCall(int i) { |
126 | return 5/i; // no-warning |
127 | } |
128 | void idcTrackZeroValueThroughCall(int x) { |
129 | idcZero(x); |
130 | idcTriggerZeroValueThroughCall(x); |
131 | } |
132 | |
133 | int idcTriggerZeroThroughDoubleAssignemnt(int i) { |
134 | return 5/i; // no-warning |
135 | } |
136 | void idcTrackZeroThroughDoubleAssignemnt(int x) { |
137 | idcZero(x); |
138 | int y = x; |
139 | int z = y; |
140 | idcTriggerZeroValueThroughCall(z); |
141 | } |
142 | |
143 | struct S { |
144 | int f1; |
145 | int f2; |
146 | }; |
147 | |
148 | void idcTrackZeroValueThroughUnaryPointerOperators(struct S *s) { |
149 | idc(s); |
150 | *(&(s->f1)) = 7; // no-warning |
151 | } |
152 | |
153 | void idcTrackZeroValueThroughUnaryPointerOperatorsWithOffset1(struct S *s) { |
154 | idc(s); |
155 | int *x = &(s->f2); |
156 | *x = 7; // no-warning |
157 | } |
158 | |
159 | void idcTrackZeroValueThroughUnaryPointerOperatorsWithOffset2(struct S *s) { |
160 | idc(s); |
161 | int *x = &(s->f2) - 1; |
162 | *x = 7; // no-warning |
163 | } |
164 | |
165 | void idcTrackZeroValueThroughUnaryPointerOperatorsWithAssignment(struct S *s) { |
166 | idc(s); |
167 | int *x = &(s->f1); |
168 | *x = 7; // no-warning |
169 | } |
170 | |
171 | void idcTrackZeroValueThroughManyUnaryPointerOperatorsWithAssignment(struct S *s) { |
172 | idc(s); |
173 | int *x = &*&(s->f1); |
174 | *x = 7; // no-warning |
175 | } |
176 | |
177 | void idcTrackZeroValueThroughManyUnaryPointerOperatorsWithAssignmentAndUnaryIncrement(struct S *s) { |
178 | idc(s); |
179 | int *x = &*&((++s)->f1); |
180 | *x = 7; // no-warning |
181 | } |
182 | |
183 | |
184 | struct S2 { |
185 | int a[1]; |
186 | }; |
187 | |
188 | void idcTrackZeroValueThroughUnaryPointerOperatorsWithArrayField(struct S2 *s) { |
189 | idc(s); |
190 | *(&(s->a[0])) = 7; // no-warning |
191 | } |
192 | |
193 | void idcTrackConstraintThroughSymbolicRegion(int **x) { |
194 | idc(*x); |
195 | // FIXME: Should not warn. |
196 | **x = 7; // expected-warning{{Dereference of null pointer}} |
197 | } |
198 | |
199 | void idcTrackConstraintThroughSymbolicRegionAndParens(int **x) { |
200 | idc(*x); |
201 | // FIXME: Should not warn. |
202 | *(*x) = 7; // expected-warning{{Dereference of null pointer}} |
203 | } |
204 | |
205 | int *idcPlainNull(int coin) { |
206 | if (coin) |
207 | return 0; |
208 | static int X; |
209 | return &X; |
210 | } |
211 | |
212 | void idcTrackZeroValueThroughSymbolicRegion(int coin, int **x) { |
213 | *x = idcPlainNull(coin); |
214 | **x = 7; // no-warning |
215 | } |
216 | |
217 | void idcTrackZeroValueThroughSymbolicRegionAndParens(int coin, int **x) { |
218 | *x = idcPlainNull(coin); |
219 | *(*x) = 7; // no-warning |
220 | } |
221 | |
222 | struct WithInt { |
223 | int i; |
224 | }; |
225 | |
226 | struct WithArray { |
227 | struct WithInt arr[1]; |
228 | }; |
229 | |
230 | struct WithArray *idcPlainNullWithArray(int coin) { |
231 | if (coin) |
232 | return 0; |
233 | static struct WithArray S; |
234 | return &S; |
235 | } |
236 | |
237 | void idcTrackZeroValueThroughSymbolicRegionWithArray(int coin, struct WithArray **s) { |
238 | *s = idcPlainNullWithArray(coin); |
239 | (*s)->arr[0].i = 1; // no-warning |
240 | // Same thing. |
241 | (*s)->arr->i = 1; // no-warning |
242 | } |
243 | |