xref: /llvm-project/clang/test/Analysis/inlining/false-positive-suppression.c (revision 0f1c1be1968076d6f96f8a7bcc4a15cf195ecd97)
1 // RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-config suppress-null-return-paths=false -verify %s
2 // RUN: %clang_analyze_cc1 -analyzer-checker=core -verify -DSUPPRESSED=1 %s
3 // RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-config avoid-suppressing-null-argument-paths=true -DSUPPRESSED=1 -DNULL_ARGS=1 -verify %s
4 
5 int opaquePropertyCheck(void *object);
6 int coin(void);
7 
getNull(void)8 int *getNull(void) {
9   return 0;
10 }
11 
12 int* getPtr(void);
13 
dynCastToInt(void * ptr)14 int *dynCastToInt(void *ptr) {
15   if (opaquePropertyCheck(ptr))
16     return (int *)ptr;
17   return 0;
18 }
19 
dynCastOrNull(void * ptr)20 int *dynCastOrNull(void *ptr) {
21   if (!ptr)
22     return 0;
23   if (opaquePropertyCheck(ptr))
24     return (int *)ptr;
25   return 0;
26 }
27 
28 
testDynCast(void * p)29 void 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 
testDynCastOrNull(void * p)37 void 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 
testBranch(void * p)46 void 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 
testBranchReversed(void * p)62 void 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 
testMultipleStore(void * p)78 void 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.
retZero(void)88 int retZero(void) {
89   return 0;
90 }
triggerDivZero(void)91 int triggerDivZero (void) {
92   int y = retZero();
93   return 5/y; // expected-warning {{Division by zero}}
94 }
95 
96 // Treat a function-like macro similarly to an inlined function, so suppress
97 // warnings along paths resulting from inlined checks.
98 #define MACRO_WITH_CHECK(a) ( ((a) != 0) ? *a : 17)
testInlineCheckInMacro(int * p)99 void testInlineCheckInMacro(int *p) {
100   int i = MACRO_WITH_CHECK(p);
101   (void)i;
102 
103   *p = 1; // no-warning
104 }
105 
106 #define MACRO_WITH_NESTED_CHECK(a) ( { int j = MACRO_WITH_CHECK(a); j; } )
testInlineCheckInNestedMacro(int * p)107 void testInlineCheckInNestedMacro(int *p) {
108   int i = MACRO_WITH_NESTED_CHECK(p);
109   (void)i;
110 
111   *p = 1; // no-warning
112 }
113 
114 #define NON_FUNCTION_MACRO_WITH_CHECK ( ((p) != 0) ? *p : 17)
testNonFunctionMacro(int * p)115 void testNonFunctionMacro(int *p) {
116   int i = NON_FUNCTION_MACRO_WITH_CHECK ;
117   (void)i;
118 
119   *p = 1; // no-warning
120 }
121 
122 
123 // This macro will dereference its argument if the argument is NULL.
124 #define MACRO_WITH_ERROR(a) ( ((a) != 0) ? 0 : *a)
testErrorInMacro(int * p)125 void testErrorInMacro(int *p) {
126   int i = MACRO_WITH_ERROR(p); // expected-warning {{Dereference of null pointer (loaded from variable 'p')}}
127   (void)i;
128 }
129 
130 // Here the check (the "if") is not in a macro, so we should still warn.
131 #define MACRO_IN_GUARD(a) (!(a))
testMacroUsedAsGuard(int * p)132 void testMacroUsedAsGuard(int *p) {
133   if (MACRO_IN_GUARD(p))
134     *p = 1; // expected-warning {{Dereference of null pointer (loaded from variable 'p')}}
135 }
136 
137 // When a nil case split is introduced in a macro and the macro is in a guard,
138 // we still shouldn't warn.
139 int isNull(int *p);
140 int isEqual(int *p, int *q);
141 #define ISNULL(ptr)    ((ptr) == 0 || isNull(ptr))
142 #define ISEQUAL(a, b)    ((int *)(a) == (int *)(b) || (ISNULL(a) && ISNULL(b)) || isEqual(a,b))
143 #define ISNOTEQUAL(a, b)   (!ISEQUAL(a, b))
testNestedDisjunctiveMacro(int * p,int * q)144 void testNestedDisjunctiveMacro(int *p, int *q) {
145   if (ISNOTEQUAL(p,q)) {
146     *p = 1; // no-warning
147     *q = 1; // no-warning
148   }
149 
150   *p = 1; // no-warning
151   *q = 1; // no-warning
152 }
153 
testNestedDisjunctiveMacro2(int * p,int * q)154 void testNestedDisjunctiveMacro2(int *p, int *q) {
155   if (ISEQUAL(p,q)) {
156     return;
157   }
158 
159   *p = 1; // no-warning
160   *q = 1; // no-warning
161 }
162 
163 
164 
165 // Here the check is entirely in non-macro code even though the code itself
166 // is a macro argument.
167 #define MACRO_DO_IT(a) (a)
testErrorInArgument(int * p)168 void testErrorInArgument(int *p) {
169   int i = MACRO_DO_IT((p ? 0 : *p)); // expected-warning {{Dereference of null pointer (loaded from variable 'p')}}c
170   (void)i;
171 }
172 
173 // No warning should be emitted if dereference is performed from a different
174 // macro.
175 #define MACRO_CHECK(a) if (a) {}
176 #define MACRO_DEREF(a) (*a)
testDifferentMacro(int * p)177 int testDifferentMacro(int *p) {
178   MACRO_CHECK(p);
179   return MACRO_DEREF(p); // no-warning
180 }
181 
182 // --------------------------
183 // "Suppression suppression"
184 // --------------------------
185 
testDynCastOrNullOfNull(void)186 void testDynCastOrNullOfNull(void) {
187   // Don't suppress when one of the arguments is NULL.
188   int *casted = dynCastOrNull(0);
189   *casted = 1;
190 #if !SUPPRESSED || NULL_ARGS
191   // expected-warning@-2 {{Dereference of null pointer}}
192 #endif
193 }
194 
testDynCastOfNull(void)195 void testDynCastOfNull(void) {
196   // Don't suppress when one of the arguments is NULL.
197   int *casted = dynCastToInt(0);
198   *casted = 1;
199 #if !SUPPRESSED || NULL_ARGS
200   // expected-warning@-2 {{Dereference of null pointer}}
201 #endif
202 }
203 
lookUpInt(int unused)204 int *lookUpInt(int unused) {
205   if (coin())
206     return 0;
207   static int x;
208   return &x;
209 }
210 
testZeroIsNotNull(void)211 void testZeroIsNotNull(void) {
212   // /Do/ suppress when the argument is 0 (an integer).
213   int *casted = lookUpInt(0);
214   *casted = 1;
215 #ifndef SUPPRESSED
216   // expected-warning@-2 {{Dereference of null pointer}}
217 #endif
218 }
219 
testTrackNull(void)220 void testTrackNull(void) {
221   // /Do/ suppress if the null argument came from another call returning null.
222   int *casted = dynCastOrNull(getNull());
223   *casted = 1;
224 #ifndef SUPPRESSED
225   // expected-warning@-2 {{Dereference of null pointer}}
226 #endif
227 }
228 
testTrackNullVariable(void)229 void testTrackNullVariable(void) {
230   // /Do/ suppress if the null argument came from another call returning null.
231   int *ptr;
232   ptr = getNull();
233   int *casted = dynCastOrNull(ptr);
234   *casted = 1;
235 #ifndef SUPPRESSED
236   // expected-warning@-2 {{Dereference of null pointer}}
237 #endif
238 }
239 
inlinedIsDifferent(int inlined)240 void inlinedIsDifferent(int inlined) {
241   int i;
242 
243   // We were erroneously picking up the inner stack frame's initialization,
244   // even though the error occurs in the outer stack frame!
245   int *p = inlined ? &i : getNull();
246 
247   if (!inlined)
248     inlinedIsDifferent(1);
249 
250   *p = 1;
251 #ifndef SUPPRESSED
252   // expected-warning@-2 {{Dereference of null pointer}}
253 #endif
254 }
255 
testInlinedIsDifferent(void)256 void testInlinedIsDifferent(void) {
257   inlinedIsDifferent(0);
258 }
259 
260 
261 // ---------------------------------------
262 // FALSE NEGATIVES (over-suppression)
263 // ---------------------------------------
264 
testNoArguments(void)265 void testNoArguments(void) {
266   // In this case the function has no branches, and MUST return null.
267   int *casted = getNull();
268   *casted = 1;
269 #ifndef SUPPRESSED
270   // expected-warning@-2 {{Dereference of null pointer}}
271 #endif
272 }
273 
getNullIfNonNull(void * input)274 int *getNullIfNonNull(void *input) {
275   if (input)
276     return 0;
277   static int x;
278   return &x;
279 }
280 
testKnownPath(void * input)281 void testKnownPath(void *input) {
282   if (!input)
283     return;
284 
285   // In this case we have a known value for the argument, and thus the path
286   // through the function doesn't ever split.
287   int *casted = getNullIfNonNull(input);
288   *casted = 1;
289 #ifndef SUPPRESSED
290   // expected-warning@-2 {{Dereference of null pointer}}
291 #endif
292 }
293 
alwaysReturnNull(void * input)294 int *alwaysReturnNull(void *input) {
295   if (opaquePropertyCheck(input))
296     return 0;
297   return 0;
298 }
299 
testAlwaysReturnNull(void * input)300 void testAlwaysReturnNull(void *input) {
301   // In this case all paths out of the function return 0, but they are all
302   // dominated by a branch whose condition we don't know!
303   int *casted = alwaysReturnNull(input);
304   *casted = 1;
305 #ifndef SUPPRESSED
306   // expected-warning@-2 {{Dereference of null pointer}}
307 #endif
308 }
309 
derefArg(int * p)310 int derefArg(int *p) {
311 	return *p;
312 #ifndef SUPPRESSED
313   // expected-warning@-2 {{Dereference of null pointer}}
314 #endif
315 }
ternaryArg(char cond)316 void ternaryArg(char cond) {
317 	static int x;
318 	derefArg(cond ? &x : getNull());
319 }
320 
derefArgCast(char * p)321 int derefArgCast(char *p) {
322 	return *p;
323 #ifndef SUPPRESSED
324   // expected-warning@-2 {{Dereference of null pointer}}
325 #endif
326 }
ternaryArgCast(char cond)327 void ternaryArgCast(char cond) {
328 	static int x;
329 	derefArgCast((char*)((unsigned)cond ? &x : getNull()));
330 }
331 
derefAssignment(int * p)332 int derefAssignment(int *p) {
333 	return *p;
334 #ifndef SUPPRESSED
335   // expected-warning@-2 {{Dereference of null pointer}}
336 #endif
337 }
338 
ternaryAssignment(char cond)339 void ternaryAssignment(char cond) {
340   static int x;
341   int *p = cond ? getNull() : getPtr();
342   derefAssignment(p);
343 }
344 
retNull(char cond)345 int *retNull(char cond) {
346   static int x;
347   return cond ? &x : getNull();
348 }
ternaryRetNull(char cond)349 int ternaryRetNull(char cond) {
350   int *p = retNull(cond);
351   return *p;
352 #ifndef SUPPRESSED
353   // expected-warning@-2 {{Dereference of null pointer}}
354 #endif
355 }
356 
357 // Test suppression of nested conditional operators.
testConditionalOperatorSuppress(int x)358 int testConditionalOperatorSuppress(int x) {
359   return *(x ? getNull() : getPtr());
360 #ifndef SUPPRESSED
361   // expected-warning@-2 {{Dereference of null pointer}}
362 #endif
363 }
testNestedConditionalOperatorSuppress(int x)364 int testNestedConditionalOperatorSuppress(int x) {
365   return *(x ? (x ? getNull() : getPtr()) : getPtr());
366 #ifndef SUPPRESSED
367   // expected-warning@-2 {{Dereference of null pointer}}
368 #endif
369 }
testConditionalOperator(int x)370 int testConditionalOperator(int x) {
371   return *(x ? 0 : getPtr()); // expected-warning {{Dereference of null pointer}}
372 }
testNestedConditionalOperator(int x)373 int testNestedConditionalOperator(int x) {
374   return *(x ? (x ? 0 : getPtr()) : getPtr()); // expected-warning {{Dereference of null pointer}}
375 }
376 
testConditionalOperatorSuppressFloatCond(float x)377 int testConditionalOperatorSuppressFloatCond(float x) {
378   return *(x ? getNull() : getPtr());
379 #ifndef SUPPRESSED
380   // expected-warning@-2 {{Dereference of null pointer}}
381 #endif
382 }
383 
384