false-positive-suppression.c revision c1bef5671e682de5a573c7c6b66871b36de0ec61
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
88// --------------------------
89// "Suppression suppression"
90// --------------------------
91
92void testDynCastOrNullOfNull() {
93  // Don't suppress when one of the arguments is NULL.
94  int *casted = dynCastOrNull(0);
95  *casted = 1;
96#if !SUPPRESSED || NULL_ARGS
97  // expected-warning@-2 {{Dereference of null pointer}}
98#endif
99}
100
101void testDynCastOfNull() {
102  // Don't suppress when one of the arguments is NULL.
103  int *casted = dynCastToInt(0);
104  *casted = 1;
105#if !SUPPRESSED || NULL_ARGS
106  // expected-warning@-2 {{Dereference of null pointer}}
107#endif
108}
109
110int *lookUpInt(int unused) {
111  if (coin())
112    return 0;
113  static int x;
114  return &x;
115}
116
117void testZeroIsNotNull() {
118  // /Do/ suppress when the argument is 0 (an integer).
119  int *casted = lookUpInt(0);
120  *casted = 1;
121#ifndef SUPPRESSED
122  // expected-warning@-2 {{Dereference of null pointer}}
123#endif
124}
125
126void testTrackNull() {
127  // /Do/ suppress if the null argument came from another call returning null.
128  int *casted = dynCastOrNull(getNull());
129  *casted = 1;
130#ifndef SUPPRESSED
131  // expected-warning@-2 {{Dereference of null pointer}}
132#endif
133}
134
135void testTrackNullVariable() {
136  // /Do/ suppress if the null argument came from another call returning null.
137  int *ptr;
138  ptr = getNull();
139  int *casted = dynCastOrNull(ptr);
140  *casted = 1;
141#ifndef SUPPRESSED
142  // expected-warning@-2 {{Dereference of null pointer}}
143#endif
144}
145
146
147// ---------------------------------------
148// FALSE NEGATIVES (over-suppression)
149// ---------------------------------------
150
151void testNoArguments() {
152  // In this case the function has no branches, and MUST return null.
153  int *casted = getNull();
154  *casted = 1;
155#ifndef SUPPRESSED
156  // expected-warning@-2 {{Dereference of null pointer}}
157#endif
158}
159
160int *getNullIfNonNull(void *input) {
161  if (input)
162    return 0;
163  static int x;
164  return &x;
165}
166
167void testKnownPath(void *input) {
168  if (!input)
169    return;
170
171  // In this case we have a known value for the argument, and thus the path
172  // through the function doesn't ever split.
173  int *casted = getNullIfNonNull(input);
174  *casted = 1;
175#ifndef SUPPRESSED
176  // expected-warning@-2 {{Dereference of null pointer}}
177#endif
178}
179
180int *alwaysReturnNull(void *input) {
181  if (opaquePropertyCheck(input))
182    return 0;
183  return 0;
184}
185
186void testAlwaysReturnNull(void *input) {
187  // In this case all paths out of the function return 0, but they are all
188  // dominated by a branch whose condition we don't know!
189  int *casted = alwaysReturnNull(input);
190  *casted = 1;
191#ifndef SUPPRESSED
192  // expected-warning@-2 {{Dereference of null pointer}}
193#endif
194}
195
196int derefArg(int *p) {
197	return *p;
198#ifndef SUPPRESSED
199  // expected-warning@-2 {{Dereference of null pointer}}
200#endif
201}
202void ternaryArg(char cond) {
203	static int x;
204	derefArg(cond ? &x : getNull());
205}
206
207int derefArgCast(char *p) {
208	return *p;
209#ifndef SUPPRESSED
210  // expected-warning@-2 {{Dereference of null pointer}}
211#endif
212}
213void ternaryArgCast(char cond) {
214	static int x;
215	derefArgCast((char*)((unsigned)cond ? &x : getNull()));
216}
217
218int derefAssignment(int *p) {
219	return *p;
220#ifndef SUPPRESSED
221  // expected-warning@-2 {{Dereference of null pointer}}
222#endif
223}
224
225void ternaryAssignment(char cond) {
226  static int x;
227  int *p = cond ? getNull() : getPtr();
228  derefAssignment(p);
229}
230
231int *retNull(char cond) {
232  static int x;
233  return cond ? &x : getNull();
234}
235int ternaryRetNull(char cond) {
236  int *p = retNull(cond);
237  return *p;
238#ifndef SUPPRESSED
239  // expected-warning@-2 {{Dereference of null pointer}}
240#endif
241}
242
243
244