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 5 int opaquePropertyCheck(void *object); 6 int coin(); 7 8 int *getNull() { 9 return 0; 10 } 11 12 int* getPtr(); 13 14 int *dynCastToInt(void *ptr) { 15 if (opaquePropertyCheck(ptr)) 16 return (int *)ptr; 17 return 0; 18 } 19 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 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 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 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 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 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. 88 int retZero() { 89 return 0; 90 } 91 int triggerDivZero () { 92 int y = retZero(); 93 return 5/y; // expected-warning {{Division by zero}} 94 } 95 96 // -------------------------- 97 // "Suppression suppression" 98 // -------------------------- 99 100 void 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 109 void 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 118 int *lookUpInt(int unused) { 119 if (coin()) 120 return 0; 121 static int x; 122 return &x; 123 } 124 125 void 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 134 void 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 143 void 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 154 void 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 170 void testInlinedIsDifferent() { 171 // <rdar://problem/13787723> 172 inlinedIsDifferent(0); 173 } 174 175 176 // --------------------------------------- 177 // FALSE NEGATIVES (over-suppression) 178 // --------------------------------------- 179 180 void 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 189 int *getNullIfNonNull(void *input) { 190 if (input) 191 return 0; 192 static int x; 193 return &x; 194 } 195 196 void 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 209 int *alwaysReturnNull(void *input) { 210 if (opaquePropertyCheck(input)) 211 return 0; 212 return 0; 213 } 214 215 void 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 225 int derefArg(int *p) { 226 return *p; 227 #ifndef SUPPRESSED 228 // expected-warning@-2 {{Dereference of null pointer}} 229 #endif 230 } 231 void ternaryArg(char cond) { 232 static int x; 233 derefArg(cond ? &x : getNull()); 234 } 235 236 int derefArgCast(char *p) { 237 return *p; 238 #ifndef SUPPRESSED 239 // expected-warning@-2 {{Dereference of null pointer}} 240 #endif 241 } 242 void ternaryArgCast(char cond) { 243 static int x; 244 derefArgCast((char*)((unsigned)cond ? &x : getNull())); 245 } 246 247 int derefAssignment(int *p) { 248 return *p; 249 #ifndef SUPPRESSED 250 // expected-warning@-2 {{Dereference of null pointer}} 251 #endif 252 } 253 254 void ternaryAssignment(char cond) { 255 static int x; 256 int *p = cond ? getNull() : getPtr(); 257 derefAssignment(p); 258 } 259 260 int *retNull(char cond) { 261 static int x; 262 return cond ? &x : getNull(); 263 } 264 int 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. 273 int testConditionalOperatorSuppress(int x) { 274 return *(x ? getNull() : getPtr()); 275 #ifndef SUPPRESSED 276 // expected-warning@-2 {{Dereference of null pointer}} 277 #endif 278 } 279 int testNestedConditionalOperatorSuppress(int x) { 280 return *(x ? (x ? getNull() : getPtr()) : getPtr()); 281 #ifndef SUPPRESSED 282 // expected-warning@-2 {{Dereference of null pointer}} 283 #endif 284 } 285 int testConditionalOperator(int x) { 286 return *(x ? 0 : getPtr()); // expected-warning {{Dereference of null pointer}} 287 } 288 int testNestedConditionalOperator(int x) { 289 return *(x ? (x ? 0 : getPtr()) : getPtr()); // expected-warning {{Dereference of null pointer}} 290 } 291 292 int testConditionalOperatorSuppressFloatCond(float x) { 293 return *(x ? getNull() : getPtr()); 294 #ifndef SUPPRESSED 295 // expected-warning@-2 {{Dereference of null pointer}} 296 #endif 297 } 298 299