1 // RUN: %clang_cc1 -analyze -analyzer-checker=osx.SecKeychainAPI %s -analyzer-ipa=inlining -verify 2 3 // Fake typedefs. 4 typedef unsigned int OSStatus; 5 typedef unsigned int SecKeychainAttributeList; 6 typedef unsigned int SecKeychainItemRef; 7 typedef unsigned int SecItemClass; 8 typedef unsigned int UInt32; 9 typedef unsigned int CFTypeRef; 10 typedef unsigned int UInt16; 11 typedef unsigned int SecProtocolType; 12 typedef unsigned int SecAuthenticationType; 13 typedef unsigned int SecKeychainAttributeInfo; 14 enum { 15 noErr = 0, 16 GenericError = 1 17 }; 18 19 // Functions that allocate data. 20 OSStatus SecKeychainItemCopyContent ( 21 SecKeychainItemRef itemRef, 22 SecItemClass *itemClass, 23 SecKeychainAttributeList *attrList, 24 UInt32 *length, 25 void **outData 26 ); 27 OSStatus SecKeychainFindGenericPassword ( 28 CFTypeRef keychainOrArray, 29 UInt32 serviceNameLength, 30 const char *serviceName, 31 UInt32 accountNameLength, 32 const char *accountName, 33 UInt32 *passwordLength, 34 void **passwordData, 35 SecKeychainItemRef *itemRef 36 ); 37 OSStatus SecKeychainFindInternetPassword ( 38 CFTypeRef keychainOrArray, 39 UInt32 serverNameLength, 40 const char *serverName, 41 UInt32 securityDomainLength, 42 const char *securityDomain, 43 UInt32 accountNameLength, 44 const char *accountName, 45 UInt32 pathLength, 46 const char *path, 47 UInt16 port, 48 SecProtocolType protocol, 49 SecAuthenticationType authenticationType, 50 UInt32 *passwordLength, 51 void **passwordData, 52 SecKeychainItemRef *itemRef 53 ); 54 OSStatus SecKeychainItemCopyAttributesAndData ( 55 SecKeychainItemRef itemRef, 56 SecKeychainAttributeInfo *info, 57 SecItemClass *itemClass, 58 SecKeychainAttributeList **attrList, 59 UInt32 *length, 60 void **outData 61 ); 62 63 // Functions which free data. 64 OSStatus SecKeychainItemFreeContent ( 65 SecKeychainAttributeList *attrList, 66 void *data 67 ); 68 OSStatus SecKeychainItemFreeAttributesAndData ( 69 SecKeychainAttributeList *attrList, 70 void *data 71 ); 72 73 void errRetVal() { 74 unsigned int *ptr = 0; 75 OSStatus st = 0; 76 UInt32 length; 77 void *outData; 78 st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData); 79 if (st == GenericError) // expected-warning{{Allocated data is not released: missing a call to 'SecKeychainItemFreeContent'.}} 80 SecKeychainItemFreeContent(ptr, outData); // expected-warning{{Only call free if a valid (non-NULL) buffer was returned}} 81 } 82 83 // If null is passed in, the data is not allocated, so no need for the matching free. 84 void fooDoNotReportNull() { 85 unsigned int *ptr = 0; 86 OSStatus st = 0; 87 UInt32 *length = 0; 88 void **outData = 0; 89 SecKeychainItemCopyContent(2, ptr, ptr, 0, 0); 90 SecKeychainItemCopyContent(2, ptr, ptr, length, outData); 91 }// no-warning 92 93 void doubleAlloc() { 94 unsigned int *ptr = 0; 95 OSStatus st = 0; 96 UInt32 length; 97 void *outData; 98 st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData); 99 st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData); // expected-warning {{Allocated data should be released before another call to the allocator:}} 100 if (st == noErr) 101 SecKeychainItemFreeContent(ptr, outData); 102 } 103 104 void fooOnlyFree() { 105 unsigned int *ptr = 0; 106 OSStatus st = 0; 107 UInt32 length; 108 void *outData = &length; 109 SecKeychainItemFreeContent(ptr, outData);// expected-warning{{Trying to free data which has not been allocated}} 110 } 111 112 // Do not warn if undefined value is passed to a function. 113 void fooOnlyFreeUndef() { 114 unsigned int *ptr = 0; 115 OSStatus st = 0; 116 UInt32 length; 117 void *outData; 118 SecKeychainItemFreeContent(ptr, outData); 119 }// no-warning 120 121 // Do not warn if the address is a parameter in the enclosing function. 122 void fooOnlyFreeParam(void *attrList, void* X) { 123 SecKeychainItemFreeContent(attrList, X); 124 }// no-warning 125 126 // If we are returning the value, do not report. 127 void* returnContent() { 128 unsigned int *ptr = 0; 129 OSStatus st = 0; 130 UInt32 length; 131 void *outData; 132 st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData); 133 return outData; 134 } // no-warning 135 136 // Password was passed in as an argument and does not have to be deleted. 137 OSStatus getPasswordAndItem(void** password, UInt32* passwordLength) { 138 OSStatus err; 139 SecKeychainItemRef item; 140 err = SecKeychainFindGenericPassword(0, 3, "xx", 3, "xx", 141 passwordLength, password, &item); 142 return err; 143 } // no-warning 144 145 // Make sure we do not report an error if we call free only if password != 0. 146 // Also, do not report double allocation if first allocation returned an error. 147 OSStatus testSecKeychainFindGenericPassword(UInt32* passwordLength, 148 CFTypeRef keychainOrArray, SecProtocolType protocol, 149 SecAuthenticationType authenticationType) { 150 OSStatus err; 151 SecKeychainItemRef item; 152 void *password; 153 err = SecKeychainFindGenericPassword(0, 3, "xx", 3, "xx", 154 passwordLength, &password, &item); 155 if( err == GenericError ) { 156 err = SecKeychainFindInternetPassword(keychainOrArray, 157 16, "server", 16, "domain", 16, "account", 158 16, "path", 222, protocol, authenticationType, 159 passwordLength, &(password), 0); 160 } 161 162 if (err == noErr && password) { 163 SecKeychainItemFreeContent(0, password); 164 } 165 return err; 166 } 167 168 int apiMismatch(SecKeychainItemRef itemRef, 169 SecKeychainAttributeInfo *info, 170 SecItemClass *itemClass) { 171 OSStatus st = 0; 172 SecKeychainAttributeList *attrList; 173 UInt32 length; 174 void *outData; 175 176 st = SecKeychainItemCopyAttributesAndData(itemRef, info, itemClass, 177 &attrList, &length, &outData); 178 if (st == noErr) 179 SecKeychainItemFreeContent(attrList, outData); // expected-warning{{Deallocator doesn't match the allocator}} 180 return 0; 181 } 182 183 int ErrorCodesFromDifferentAPISDoNotInterfere(SecKeychainItemRef itemRef, 184 SecKeychainAttributeInfo *info, 185 SecItemClass *itemClass) { 186 unsigned int *ptr = 0; 187 OSStatus st = 0; 188 UInt32 length; 189 void *outData; 190 OSStatus st2 = 0; 191 SecKeychainAttributeList *attrList; 192 UInt32 length2; 193 void *outData2; 194 195 st2 = SecKeychainItemCopyAttributesAndData(itemRef, info, itemClass, 196 &attrList, &length2, &outData2); 197 st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData); 198 if (st == noErr) { 199 SecKeychainItemFreeContent(ptr, outData); 200 if (st2 == noErr) { 201 SecKeychainItemFreeAttributesAndData(attrList, outData2); 202 } 203 } 204 return 0; // expected-warning{{Allocated data is not released: missing a call to 'SecKeychainItemFreeAttributesAndData'}} 205 } 206 207 int foo(CFTypeRef keychainOrArray, SecProtocolType protocol, 208 SecAuthenticationType authenticationType, SecKeychainItemRef *itemRef) { 209 unsigned int *ptr = 0; 210 OSStatus st = 0; 211 212 UInt32 length; 213 void *outData[5]; 214 215 st = SecKeychainFindInternetPassword(keychainOrArray, 216 16, "server", 16, "domain", 16, "account", 217 16, "path", 222, protocol, authenticationType, 218 &length, &(outData[3]), itemRef); 219 if (length == 5) { 220 if (st == noErr) 221 SecKeychainItemFreeContent(ptr, outData[3]); 222 } 223 if (length) { // expected-warning{{Allocated data is not released: missing a call to 'SecKeychainItemFreeContent'.}} 224 length++; 225 } 226 return 0; 227 }// no-warning 228 229 void free(void *ptr); 230 void deallocateWithFree() { 231 unsigned int *ptr = 0; 232 OSStatus st = 0; 233 UInt32 length; 234 void *outData; 235 st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData); 236 if (st == noErr) 237 free(outData); // expected-warning{{Deallocator doesn't match the allocator: 'SecKeychainItemFreeContent' should be used}} 238 } 239 240 // Typesdefs for CFStringCreateWithBytesNoCopy. 241 typedef char uint8_t; 242 typedef signed long CFIndex; 243 typedef UInt32 CFStringEncoding; 244 typedef unsigned Boolean; 245 typedef const struct __CFString * CFStringRef; 246 typedef const struct __CFAllocator * CFAllocatorRef; 247 extern const CFAllocatorRef kCFAllocatorDefault; 248 extern const CFAllocatorRef kCFAllocatorSystemDefault; 249 extern const CFAllocatorRef kCFAllocatorMalloc; 250 extern const CFAllocatorRef kCFAllocatorMallocZone; 251 extern const CFAllocatorRef kCFAllocatorNull; 252 extern const CFAllocatorRef kCFAllocatorUseContext; 253 CFStringRef CFStringCreateWithBytesNoCopy(CFAllocatorRef alloc, const uint8_t *bytes, CFIndex numBytes, CFStringEncoding encoding, Boolean externalFormat, CFAllocatorRef contentsDeallocator); 254 extern void CFRelease(CFStringRef cf); 255 256 void DellocWithCFStringCreate1(CFAllocatorRef alloc) { 257 unsigned int *ptr = 0; 258 OSStatus st = 0; 259 UInt32 length; 260 void *bytes; 261 char * x; 262 st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &bytes); 263 if (st == noErr) { 264 CFStringRef userStr = CFStringCreateWithBytesNoCopy(alloc, bytes, length, 5, 0, kCFAllocatorDefault); // expected-warning{{Deallocator doesn't match the allocator:}} 265 CFRelease(userStr); 266 } 267 } 268 269 void DellocWithCFStringCreate2(CFAllocatorRef alloc) { 270 unsigned int *ptr = 0; 271 OSStatus st = 0; 272 UInt32 length; 273 void *bytes; 274 char * x; 275 st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &bytes); 276 if (st == noErr) { 277 CFStringRef userStr = CFStringCreateWithBytesNoCopy(alloc, bytes, length, 5, 0, kCFAllocatorNull); // expected-warning{{Allocated data is not released}} 278 CFRelease(userStr); 279 } 280 } 281 282 void DellocWithCFStringCreate3(CFAllocatorRef alloc) { 283 unsigned int *ptr = 0; 284 OSStatus st = 0; 285 UInt32 length; 286 void *bytes; 287 char * x; 288 st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &bytes); 289 if (st == noErr) { 290 CFStringRef userStr = CFStringCreateWithBytesNoCopy(alloc, bytes, length, 5, 0, kCFAllocatorUseContext); 291 CFRelease(userStr); 292 } 293 } 294 295 void DellocWithCFStringCreate4(CFAllocatorRef alloc) { 296 unsigned int *ptr = 0; 297 OSStatus st = 0; 298 UInt32 length; 299 void *bytes; 300 char * x; 301 st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &bytes); 302 if (st == noErr) { 303 CFStringRef userStr = CFStringCreateWithBytesNoCopy(alloc, bytes, length, 5, 0, 0); // expected-warning{{Deallocator doesn't match the allocator:}} 304 CFRelease(userStr); 305 } 306 } 307 308 void radar10508828() { 309 UInt32 pwdLen = 0; 310 void* pwdBytes = 0; 311 OSStatus rc = SecKeychainFindGenericPassword(0, 3, "foo", 3, "bar", &pwdLen, &pwdBytes, 0); 312 #pragma unused(rc) 313 if (pwdBytes) 314 SecKeychainItemFreeContent(0, pwdBytes); 315 } 316 317 void radar10508828_2() { 318 UInt32 pwdLen = 0; 319 void* pwdBytes = 0; 320 OSStatus rc = SecKeychainFindGenericPassword(0, 3, "foo", 3, "bar", &pwdLen, &pwdBytes, 0); 321 SecKeychainItemFreeContent(0, pwdBytes); // expected-warning {{Only call free if a valid (non-NULL) buffer was returned.}} 322 } 323 324 //Example from bug 10797. 325 __inline__ static 326 const char *__WBASLLevelString(int level) { 327 return "foo"; 328 } 329 330 static int *bug10798(int *p, int columns, int prevRow) { 331 int *row = 0; 332 row = p + prevRow * columns; 333 prevRow += 2; 334 do { 335 ++prevRow; 336 row+=columns; 337 } while(10 >= row[1]); 338 return row; 339 } 340 341 // Test inter-procedural behaviour. 342 343 void my_FreeParam(void *attrList, void* X) { 344 SecKeychainItemFreeContent(attrList, X); 345 } 346 347 void *my_AllocateReturn(OSStatus *st) { 348 unsigned int *ptr = 0; 349 UInt32 length; 350 void *outData; 351 *st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData); 352 return outData; 353 } 354 355 OSStatus my_Allocate_Param(void** password, UInt32* passwordLength) { 356 OSStatus err; 357 SecKeychainItemRef item; 358 err = SecKeychainFindGenericPassword(0, 3, "xx", 3, "xx", 359 passwordLength, password, &item); 360 return err; 361 } 362 363 void allocAndFree1() { 364 unsigned int *ptr = 0; 365 OSStatus st = 0; 366 UInt32 length; 367 void *outData; 368 st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData); 369 if (st == noErr) 370 my_FreeParam(ptr, outData); 371 } 372 373 void consumeChar(char); 374 375 void allocNoFree2(int x) { 376 OSStatus st = 0; 377 void *outData = my_AllocateReturn(&st); 378 if (x) { 379 consumeChar(*(char*)outData); // expected-warning{{Allocated data is not released:}} 380 return; 381 } else { 382 consumeChar(*(char*)outData); 383 } 384 return; 385 } 386 387 void allocAndFree2(void *attrList) { 388 OSStatus st = 0; 389 void *outData = my_AllocateReturn(&st); 390 if (st == noErr) 391 my_FreeParam(attrList, outData); 392 } 393 394 void allocNoFree3() { 395 UInt32 length = 32; 396 void *outData; 397 void *outData2; 398 OSStatus st = my_Allocate_Param(&outData, &length); // expected-warning{{Allocated data is not released}} 399 st = my_Allocate_Param(&outData2, &length); // expected-warning{{Allocated data is not released}} 400 } 401 402 void allocAndFree3(void *attrList) { 403 UInt32 length = 32; 404 void *outData; 405 OSStatus st = my_Allocate_Param(&outData, &length); 406 if (st == noErr) 407 SecKeychainItemFreeContent(attrList, outData); 408 } 409 410