false-positive-suppression.c revision f510f5cd57fa9b7ea6f6e103c65c0df95a55d986
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 *dynCastToInt(void *ptr) {
13  if (opaquePropertyCheck(ptr))
14    return (int *)ptr;
15  return 0;
16}
17
18int *dynCastOrNull(void *ptr) {
19  if (!ptr)
20    return 0;
21  if (opaquePropertyCheck(ptr))
22    return (int *)ptr;
23  return 0;
24}
25
26
27void testDynCast(void *p) {
28  int *casted = dynCastToInt(p);
29  *casted = 1;
30#ifndef SUPPRESSED
31  // expected-warning@-2 {{Dereference of null pointer}}
32#endif
33}
34
35void testDynCastOrNull(void *p) {
36  int *casted = dynCastOrNull(p);
37  *casted = 1;
38#ifndef SUPPRESSED
39  // expected-warning@-2 {{Dereference of null pointer}}
40#endif
41}
42
43
44void testBranch(void *p) {
45  int *casted;
46
47  // Although the report will be suppressed on one branch, it should still be
48  // valid on the other.
49  if (coin()) {
50    casted = dynCastToInt(p);
51  } else {
52    if (p)
53      return;
54    casted = (int *)p;
55  }
56
57  *casted = 1; // expected-warning {{Dereference of null pointer}}
58}
59
60void testBranchReversed(void *p) {
61  int *casted;
62
63  // Although the report will be suppressed on one branch, it should still be
64  // valid on the other.
65  if (coin()) {
66    if (p)
67      return;
68    casted = (int *)p;
69  } else {
70    casted = dynCastToInt(p);
71  }
72
73  *casted = 1; // expected-warning {{Dereference of null pointer}}
74}
75
76void testMultipleStore(void *p) {
77  int *casted = 0;
78  casted = dynCastToInt(p);
79  *casted = 1;
80#ifndef SUPPRESSED
81  // expected-warning@-2 {{Dereference of null pointer}}
82#endif
83}
84
85
86// --------------------------
87// "Suppression suppression"
88// --------------------------
89
90void testDynCastOrNullOfNull() {
91  // Don't suppress when one of the arguments is NULL.
92  int *casted = dynCastOrNull(0);
93  *casted = 1;
94#if !SUPPRESSED || NULL_ARGS
95  // expected-warning@-2 {{Dereference of null pointer}}
96#endif
97}
98
99void testDynCastOfNull() {
100  // Don't suppress when one of the arguments is NULL.
101  int *casted = dynCastToInt(0);
102  *casted = 1;
103#if !SUPPRESSED || NULL_ARGS
104  // expected-warning@-2 {{Dereference of null pointer}}
105#endif
106}
107
108int *lookUpInt(int unused) {
109  if (coin())
110    return 0;
111  static int x;
112  return &x;
113}
114
115void testZeroIsNotNull() {
116  // /Do/ suppress when the argument is 0 (an integer).
117  int *casted = lookUpInt(0);
118  *casted = 1;
119#ifndef SUPPRESSED
120  // expected-warning@-2 {{Dereference of null pointer}}
121#endif
122}
123
124void testTrackNull() {
125  // /Do/ suppress if the null argument came from another call returning null.
126  int *casted = dynCastOrNull(getNull());
127  *casted = 1;
128#ifndef SUPPRESSED
129  // expected-warning@-2 {{Dereference of null pointer}}
130#endif
131}
132
133void testTrackNullVariable() {
134  // /Do/ suppress if the null argument came from another call returning null.
135  int *ptr;
136  ptr = getNull();
137  int *casted = dynCastOrNull(ptr);
138  *casted = 1;
139#ifndef SUPPRESSED
140  // expected-warning@-2 {{Dereference of null pointer}}
141#endif
142}
143
144
145// ---------------------------------------
146// FALSE NEGATIVES (over-suppression)
147// ---------------------------------------
148
149void testNoArguments() {
150  // In this case the function has no branches, and MUST return null.
151  int *casted = getNull();
152  *casted = 1;
153#ifndef SUPPRESSED
154  // expected-warning@-2 {{Dereference of null pointer}}
155#endif
156}
157
158int *getNullIfNonNull(void *input) {
159  if (input)
160    return 0;
161  static int x;
162  return &x;
163}
164
165void testKnownPath(void *input) {
166  if (!input)
167    return;
168
169  // In this case we have a known value for the argument, and thus the path
170  // through the function doesn't ever split.
171  int *casted = getNullIfNonNull(input);
172  *casted = 1;
173#ifndef SUPPRESSED
174  // expected-warning@-2 {{Dereference of null pointer}}
175#endif
176}
177
178int *alwaysReturnNull(void *input) {
179  if (opaquePropertyCheck(input))
180    return 0;
181  return 0;
182}
183
184void testAlwaysReturnNull(void *input) {
185  // In this case all paths out of the function return 0, but they are all
186  // dominated by a branch whose condition we don't know!
187  int *casted = alwaysReturnNull(input);
188  *casted = 1;
189#ifndef SUPPRESSED
190  // expected-warning@-2 {{Dereference of null pointer}}
191#endif
192}
193
194int derefArg(int *p) {
195	return *p;
196#ifndef SUPPRESSED
197  // expected-warning@-2 {{Dereference of null pointer}}
198#endif
199}
200void ternaryArg(char cond) {
201	static int x;
202	derefArg(cond ? &x : getNull());
203}
204
205int derefArgCast(char *p) {
206	return *p;
207#ifndef SUPPRESSED
208  // expected-warning@-2 {{Dereference of null pointer}}
209#endif
210}
211void ternaryArgCast(char cond) {
212	static int x;
213	derefArgCast((char*)((unsigned)cond ? &x : getNull()));
214}
215
216int derefAssignment(int *p) {
217	return *p;
218#ifndef SUPPRESSED
219  // expected-warning@-2 {{Dereference of null pointer}}
220#endif
221}
222void ternaryAssignment(char cond) {
223  static int x;
224  int *p = cond ? &x : getNull();
225  derefAssignment(p);
226}
227
228int *retNull(char cond) {
229  static int x;
230  return cond ? &x : getNull();
231}
232int ternaryRetNull(char cond) {
233  int *p = retNull(cond);
234  return *p;
235#ifndef SUPPRESSED
236  // expected-warning@-2 {{Dereference of null pointer}}
237#endif
238}
239
240
241