false-positive-suppression.c revision 7f79b78351af03a392ee16d8ec557d47746c33c6
1// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-config suppress-null-return-paths=false -verify %s
2// RUN: %clang_cc1 -analyze -analyzer-checker=core -verify -DSUPPRESSED=1 %s
3// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-config avoid-suppressing-null-argument-paths=true -DSUPPRESSED=1 -DNULL_ARGS=1 -verify %s
4
5int opaquePropertyCheck(void *object);
6int coin();
7
8int *getNull() {
9  return 0;
10}
11
12int* getPtr();
13
14int *dynCastToInt(void *ptr) {
15  if (opaquePropertyCheck(ptr))
16    return (int *)ptr;
17  return 0;
18}
19
20int *dynCastOrNull(void *ptr) {
21  if (!ptr)
22    return 0;
23  if (opaquePropertyCheck(ptr))
24    return (int *)ptr;
25  return 0;
26}
27
28
29void testDynCast(void *p) {
30  int *casted = dynCastToInt(p);
31  *casted = 1;
32#ifndef SUPPRESSED
33  // expected-warning@-2 {{Dereference of null pointer}}
34#endif
35}
36
37void testDynCastOrNull(void *p) {
38  int *casted = dynCastOrNull(p);
39  *casted = 1;
40#ifndef SUPPRESSED
41  // expected-warning@-2 {{Dereference of null pointer}}
42#endif
43}
44
45
46void testBranch(void *p) {
47  int *casted;
48
49  // Although the report will be suppressed on one branch, it should still be
50  // valid on the other.
51  if (coin()) {
52    casted = dynCastToInt(p);
53  } else {
54    if (p)
55      return;
56    casted = (int *)p;
57  }
58
59  *casted = 1; // expected-warning {{Dereference of null pointer}}
60}
61
62void testBranchReversed(void *p) {
63  int *casted;
64
65  // Although the report will be suppressed on one branch, it should still be
66  // valid on the other.
67  if (coin()) {
68    if (p)
69      return;
70    casted = (int *)p;
71  } else {
72    casted = dynCastToInt(p);
73  }
74
75  *casted = 1; // expected-warning {{Dereference of null pointer}}
76}
77
78void testMultipleStore(void *p) {
79  int *casted = 0;
80  casted = dynCastToInt(p);
81  *casted = 1;
82#ifndef SUPPRESSED
83  // expected-warning@-2 {{Dereference of null pointer}}
84#endif
85}
86
87// Test that div by zero does not get suppressed. This is a policy choice.
88int retZero() {
89  return 0;
90}
91int triggerDivZero () {
92  int y = retZero();
93  return 5/y; // expected-warning {{Division by zero}}
94}
95
96// --------------------------
97// "Suppression suppression"
98// --------------------------
99
100void testDynCastOrNullOfNull() {
101  // Don't suppress when one of the arguments is NULL.
102  int *casted = dynCastOrNull(0);
103  *casted = 1;
104#if !SUPPRESSED || NULL_ARGS
105  // expected-warning@-2 {{Dereference of null pointer}}
106#endif
107}
108
109void testDynCastOfNull() {
110  // Don't suppress when one of the arguments is NULL.
111  int *casted = dynCastToInt(0);
112  *casted = 1;
113#if !SUPPRESSED || NULL_ARGS
114  // expected-warning@-2 {{Dereference of null pointer}}
115#endif
116}
117
118int *lookUpInt(int unused) {
119  if (coin())
120    return 0;
121  static int x;
122  return &x;
123}
124
125void testZeroIsNotNull() {
126  // /Do/ suppress when the argument is 0 (an integer).
127  int *casted = lookUpInt(0);
128  *casted = 1;
129#ifndef SUPPRESSED
130  // expected-warning@-2 {{Dereference of null pointer}}
131#endif
132}
133
134void testTrackNull() {
135  // /Do/ suppress if the null argument came from another call returning null.
136  int *casted = dynCastOrNull(getNull());
137  *casted = 1;
138#ifndef SUPPRESSED
139  // expected-warning@-2 {{Dereference of null pointer}}
140#endif
141}
142
143void testTrackNullVariable() {
144  // /Do/ suppress if the null argument came from another call returning null.
145  int *ptr;
146  ptr = getNull();
147  int *casted = dynCastOrNull(ptr);
148  *casted = 1;
149#ifndef SUPPRESSED
150  // expected-warning@-2 {{Dereference of null pointer}}
151#endif
152}
153
154void inlinedIsDifferent(int inlined) {
155  int i;
156
157  // We were erroneously picking up the inner stack frame's initialization,
158  // even though the error occurs in the outer stack frame!
159  int *p = inlined ? &i : getNull();
160
161  if (!inlined)
162    inlinedIsDifferent(1);
163
164  *p = 1;
165#ifndef SUPPRESSED
166  // expected-warning@-2 {{Dereference of null pointer}}
167#endif
168}
169
170void testInlinedIsDifferent() {
171  // <rdar://problem/13787723>
172  inlinedIsDifferent(0);
173}
174
175
176// ---------------------------------------
177// FALSE NEGATIVES (over-suppression)
178// ---------------------------------------
179
180void testNoArguments() {
181  // In this case the function has no branches, and MUST return null.
182  int *casted = getNull();
183  *casted = 1;
184#ifndef SUPPRESSED
185  // expected-warning@-2 {{Dereference of null pointer}}
186#endif
187}
188
189int *getNullIfNonNull(void *input) {
190  if (input)
191    return 0;
192  static int x;
193  return &x;
194}
195
196void testKnownPath(void *input) {
197  if (!input)
198    return;
199
200  // In this case we have a known value for the argument, and thus the path
201  // through the function doesn't ever split.
202  int *casted = getNullIfNonNull(input);
203  *casted = 1;
204#ifndef SUPPRESSED
205  // expected-warning@-2 {{Dereference of null pointer}}
206#endif
207}
208
209int *alwaysReturnNull(void *input) {
210  if (opaquePropertyCheck(input))
211    return 0;
212  return 0;
213}
214
215void testAlwaysReturnNull(void *input) {
216  // In this case all paths out of the function return 0, but they are all
217  // dominated by a branch whose condition we don't know!
218  int *casted = alwaysReturnNull(input);
219  *casted = 1;
220#ifndef SUPPRESSED
221  // expected-warning@-2 {{Dereference of null pointer}}
222#endif
223}
224
225int derefArg(int *p) {
226	return *p;
227#ifndef SUPPRESSED
228  // expected-warning@-2 {{Dereference of null pointer}}
229#endif
230}
231void ternaryArg(char cond) {
232	static int x;
233	derefArg(cond ? &x : getNull());
234}
235
236int derefArgCast(char *p) {
237	return *p;
238#ifndef SUPPRESSED
239  // expected-warning@-2 {{Dereference of null pointer}}
240#endif
241}
242void ternaryArgCast(char cond) {
243	static int x;
244	derefArgCast((char*)((unsigned)cond ? &x : getNull()));
245}
246
247int derefAssignment(int *p) {
248	return *p;
249#ifndef SUPPRESSED
250  // expected-warning@-2 {{Dereference of null pointer}}
251#endif
252}
253
254void ternaryAssignment(char cond) {
255  static int x;
256  int *p = cond ? getNull() : getPtr();
257  derefAssignment(p);
258}
259
260int *retNull(char cond) {
261  static int x;
262  return cond ? &x : getNull();
263}
264int ternaryRetNull(char cond) {
265  int *p = retNull(cond);
266  return *p;
267#ifndef SUPPRESSED
268  // expected-warning@-2 {{Dereference of null pointer}}
269#endif
270}
271
272// Test suppression of nested conditional operators.
273int testConditionalOperatorSuppress(int x) {
274  return *(x ? getNull() : getPtr());
275#ifndef SUPPRESSED
276  // expected-warning@-2 {{Dereference of null pointer}}
277#endif
278}
279int testNestedConditionalOperatorSuppress(int x) {
280  return *(x ? (x ? getNull() : getPtr()) : getPtr());
281#ifndef SUPPRESSED
282  // expected-warning@-2 {{Dereference of null pointer}}
283#endif
284}
285int testConditionalOperator(int x) {
286  return *(x ? 0 : getPtr()); // expected-warning {{Dereference of null pointer}}
287}
288int testNestedConditionalOperator(int x) {
289  return *(x ? (x ? 0 : getPtr()) : getPtr()); // expected-warning {{Dereference of null pointer}}
290}
291
292int testConditionalOperatorSuppressFloatCond(float x) {
293  return *(x ? getNull() : getPtr());
294#ifndef SUPPRESSED
295  // expected-warning@-2 {{Dereference of null pointer}}
296#endif
297}
298
299