1// RUN: %clang_cc1 -analyze -analyzer-checker=osx.SecKeychainAPI %s -verify 2 3// Fake typedefs. 4typedef unsigned int OSStatus; 5typedef unsigned int SecKeychainAttributeList; 6typedef unsigned int SecKeychainItemRef; 7typedef unsigned int SecItemClass; 8typedef unsigned int UInt32; 9typedef unsigned int CFTypeRef; 10typedef unsigned int UInt16; 11typedef unsigned int SecProtocolType; 12typedef unsigned int SecAuthenticationType; 13typedef unsigned int SecKeychainAttributeInfo; 14enum { 15 noErr = 0, 16 GenericError = 1 17}; 18 19// Functions that allocate data. 20OSStatus SecKeychainItemCopyContent ( 21 SecKeychainItemRef itemRef, 22 SecItemClass *itemClass, 23 SecKeychainAttributeList *attrList, 24 UInt32 *length, 25 void **outData 26); 27OSStatus 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); 37OSStatus 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); 54OSStatus 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. 64OSStatus SecKeychainItemFreeContent ( 65 SecKeychainAttributeList *attrList, 66 void *data 67); 68OSStatus SecKeychainItemFreeAttributesAndData ( 69 SecKeychainAttributeList *attrList, 70 void *data 71); 72 73void 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) 80 SecKeychainItemFreeContent(ptr, outData); // expected-warning{{Only call free if a valid (non-NULL) buffer was returned}} 81} // expected-warning{{Allocated data is not released: missing a call to 'SecKeychainItemFreeContent'}} 82 83// If null is passed in, the data is not allocated, so no need for the matching free. 84void 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 93void 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 104void 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. 113void 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. 122void fooOnlyFreeParam(void *attrList, void* X) { 123 SecKeychainItemFreeContent(attrList, X); 124}// no-warning 125 126// If we are returning the value, do not report. 127void* 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. 137OSStatus 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. 147OSStatus 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 168int 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 183int 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 207int 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 229void free(void *ptr); 230void 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. 241typedef char uint8_t; 242typedef signed long CFIndex; 243typedef UInt32 CFStringEncoding; 244typedef unsigned Boolean; 245typedef const struct __CFString * CFStringRef; 246typedef const struct __CFAllocator * CFAllocatorRef; 247extern const CFAllocatorRef kCFAllocatorDefault; 248extern const CFAllocatorRef kCFAllocatorSystemDefault; 249extern const CFAllocatorRef kCFAllocatorMalloc; 250extern const CFAllocatorRef kCFAllocatorMallocZone; 251extern const CFAllocatorRef kCFAllocatorNull; 252extern const CFAllocatorRef kCFAllocatorUseContext; 253CFStringRef CFStringCreateWithBytesNoCopy(CFAllocatorRef alloc, const uint8_t *bytes, CFIndex numBytes, CFStringEncoding encoding, Boolean externalFormat, CFAllocatorRef contentsDeallocator); 254extern void CFRelease(CFStringRef cf); 255 256void 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 269void 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 282void 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 295void 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 308static CFAllocatorRef gKeychainDeallocator = 0; 309 310static CFAllocatorRef GetKeychainDeallocator() { 311 return gKeychainDeallocator; 312} 313 314CFStringRef DellocWithCFStringCreate5(CFAllocatorRef alloc) { 315 unsigned int *ptr = 0; 316 OSStatus st = 0; 317 UInt32 length; 318 void *bytes; 319 char * x; 320 st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &bytes); 321 if (st == noErr) { 322 return CFStringCreateWithBytesNoCopy(alloc, bytes, length, 5, 0, GetKeychainDeallocator()); // no-warning 323 } 324 return 0; 325} 326 327void radar10508828() { 328 UInt32 pwdLen = 0; 329 void* pwdBytes = 0; 330 OSStatus rc = SecKeychainFindGenericPassword(0, 3, "foo", 3, "bar", &pwdLen, &pwdBytes, 0); 331#pragma unused(rc) 332 if (pwdBytes) 333 SecKeychainItemFreeContent(0, pwdBytes); 334} 335 336void radar10508828_2() { 337 UInt32 pwdLen = 0; 338 void* pwdBytes = 0; 339 OSStatus rc = SecKeychainFindGenericPassword(0, 3, "foo", 3, "bar", &pwdLen, &pwdBytes, 0); 340 SecKeychainItemFreeContent(0, pwdBytes); // expected-warning {{Only call free if a valid (non-NULL) buffer was returned}} 341} 342 343//Example from bug 10797. 344__inline__ static 345const char *__WBASLLevelString(int level) { 346 return "foo"; 347} 348 349static int *bug10798(int *p, int columns, int prevRow) { 350 int *row = 0; 351 row = p + prevRow * columns; 352 prevRow += 2; 353 do { 354 ++prevRow; 355 row+=columns; 356 } while(10 >= row[1]); 357 return row; 358} 359 360// Test inter-procedural behaviour. 361 362void my_FreeParam(void *attrList, void* X) { 363 SecKeychainItemFreeContent(attrList, X); 364} 365 366void *my_AllocateReturn(OSStatus *st) { 367 unsigned int *ptr = 0; 368 UInt32 length; 369 void *outData; 370 *st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData); 371 return outData; 372} 373 374OSStatus my_Allocate_Param(void** password, UInt32* passwordLength) { 375 OSStatus err; 376 SecKeychainItemRef item; 377 err = SecKeychainFindGenericPassword(0, 3, "xx", 3, "xx", 378 passwordLength, password, &item); 379 return err; 380} 381 382void allocAndFree1() { 383 unsigned int *ptr = 0; 384 OSStatus st = 0; 385 UInt32 length; 386 void *outData; 387 st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData); 388 if (st == noErr) 389 my_FreeParam(ptr, outData); 390} 391 392void consumeChar(char); 393 394void allocNoFree2(int x) { 395 OSStatus st = 0; 396 void *outData = my_AllocateReturn(&st); 397 if (x) { 398 consumeChar(*(char*)outData); // expected-warning{{Allocated data is not released:}} 399 return; 400 } else { 401 consumeChar(*(char*)outData); 402 } 403 return; 404} 405 406void allocAndFree2(void *attrList) { 407 OSStatus st = 0; 408 void *outData = my_AllocateReturn(&st); 409 if (st == noErr) 410 my_FreeParam(attrList, outData); 411} 412 413void allocNoFree3() { 414 UInt32 length = 32; 415 void *outData; 416 void *outData2; 417 OSStatus st = my_Allocate_Param(&outData, &length); // expected-warning{{Allocated data is not released}} 418 st = my_Allocate_Param(&outData2, &length); // expected-warning{{Allocated data is not released}} 419} 420 421void allocAndFree3(void *attrList) { 422 UInt32 length = 32; 423 void *outData; 424 OSStatus st = my_Allocate_Param(&outData, &length); 425 if (st == noErr) 426 SecKeychainItemFreeContent(attrList, outData); 427} 428 429