1// RUN: %clang_analyze_cc1 -analyzer-checker=osx.SecKeychainAPI -fblocks %s -verify 2 3#include "Inputs/system-header-simulator-objc.h" 4 5// Fake typedefs. 6typedef unsigned int OSStatus; 7typedef unsigned int SecKeychainAttributeList; 8typedef unsigned int SecKeychainItemRef; 9typedef unsigned int SecItemClass; 10typedef unsigned int UInt32; 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); 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 104// Do not warn if undefined value is passed to a function. 105void fooOnlyFreeUndef() { 106 unsigned int *ptr = 0; 107 OSStatus st = 0; 108 UInt32 length; 109 void *outData; 110 SecKeychainItemFreeContent(ptr, outData); 111}// no-warning 112 113// Do not warn if the address is a parameter in the enclosing function. 114void fooOnlyFreeParam(void *attrList, void* X) { 115 SecKeychainItemFreeContent(attrList, X); 116}// no-warning 117 118// If we are returning the value, do not report. 119void* returnContent() { 120 unsigned int *ptr = 0; 121 OSStatus st = 0; 122 UInt32 length; 123 void *outData; 124 st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData); 125 return outData; 126} // no-warning 127 128// Password was passed in as an argument and does not have to be deleted. 129OSStatus getPasswordAndItem(void** password, UInt32* passwordLength) { 130 OSStatus err; 131 SecKeychainItemRef item; 132 err = SecKeychainFindGenericPassword(0, 3, "xx", 3, "xx", 133 passwordLength, password, &item); 134 return err; 135} // no-warning 136 137// Make sure we do not report an error if we call free only if password != 0. 138// Also, do not report double allocation if first allocation returned an error. 139OSStatus testSecKeychainFindGenericPassword(UInt32* passwordLength, 140 CFTypeRef keychainOrArray, SecProtocolType protocol, 141 SecAuthenticationType authenticationType) { 142 OSStatus err; 143 SecKeychainItemRef item; 144 void *password; 145 err = SecKeychainFindGenericPassword(0, 3, "xx", 3, "xx", 146 passwordLength, &password, &item); 147 if( err == GenericError ) { 148 err = SecKeychainFindInternetPassword(keychainOrArray, 149 16, "server", 16, "domain", 16, "account", 150 16, "path", 222, protocol, authenticationType, 151 passwordLength, &(password), 0); 152 } 153 154 if (err == noErr && password) { 155 SecKeychainItemFreeContent(0, password); 156 } 157 return err; 158} 159 160int apiMismatch(SecKeychainItemRef itemRef, 161 SecKeychainAttributeInfo *info, 162 SecItemClass *itemClass) { 163 OSStatus st = 0; 164 SecKeychainAttributeList *attrList; 165 UInt32 length; 166 void *outData; 167 168 st = SecKeychainItemCopyAttributesAndData(itemRef, info, itemClass, 169 &attrList, &length, &outData); 170 if (st == noErr) 171 SecKeychainItemFreeContent(attrList, outData); // expected-warning{{Deallocator doesn't match the allocator}} 172 return 0; 173} 174 175int ErrorCodesFromDifferentAPISDoNotInterfere(SecKeychainItemRef itemRef, 176 SecKeychainAttributeInfo *info, 177 SecItemClass *itemClass) { 178 unsigned int *ptr = 0; 179 OSStatus st = 0; 180 UInt32 length; 181 void *outData; 182 OSStatus st2 = 0; 183 SecKeychainAttributeList *attrList; 184 UInt32 length2; 185 void *outData2; 186 187 st2 = SecKeychainItemCopyAttributesAndData(itemRef, info, itemClass, 188 &attrList, &length2, &outData2); 189 st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData); 190 if (st == noErr) { 191 SecKeychainItemFreeContent(ptr, outData); 192 if (st2 == noErr) { 193 SecKeychainItemFreeAttributesAndData(attrList, outData2); 194 } 195 } 196 return 0; // expected-warning{{Allocated data is not released: missing a call to 'SecKeychainItemFreeAttributesAndData'}} 197} 198 199int foo(CFTypeRef keychainOrArray, SecProtocolType protocol, 200 SecAuthenticationType authenticationType, SecKeychainItemRef *itemRef) { 201 unsigned int *ptr = 0; 202 OSStatus st = 0; 203 204 UInt32 length; 205 void *outData[5]; 206 207 st = SecKeychainFindInternetPassword(keychainOrArray, 208 16, "server", 16, "domain", 16, "account", 209 16, "path", 222, protocol, authenticationType, 210 &length, &(outData[3]), itemRef); 211 if (length == 5) { 212 if (st == noErr) 213 SecKeychainItemFreeContent(ptr, outData[3]); 214 } 215 if (length) { // expected-warning{{Allocated data is not released: missing a call to 'SecKeychainItemFreeContent'}} 216 length++; 217 } 218 return 0; 219} 220 221int testErrorCodeAsLHS(CFTypeRef keychainOrArray, SecProtocolType protocol, 222 SecAuthenticationType authenticationType, SecKeychainItemRef *itemRef) { 223 unsigned int *ptr = 0; 224 OSStatus st = 0; 225 UInt32 length; 226 void *outData; 227 st = SecKeychainFindInternetPassword(keychainOrArray, 228 16, "server", 16, "domain", 16, "account", 229 16, "path", 222, protocol, authenticationType, 230 &length, &outData, itemRef); 231 if (noErr == st) 232 SecKeychainItemFreeContent(ptr, outData); 233 234 return 0; 235} 236 237void free(void *ptr); 238void deallocateWithFree() { 239 unsigned int *ptr = 0; 240 OSStatus st = 0; 241 UInt32 length; 242 void *outData; 243 st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData); 244 if (st == noErr) 245 free(outData); // expected-warning{{Deallocator doesn't match the allocator: 'SecKeychainItemFreeContent' should be used}} 246} 247 248// Typesdefs for CFStringCreateWithBytesNoCopy. 249typedef char uint8_t; 250typedef signed long CFIndex; 251typedef UInt32 CFStringEncoding; 252typedef unsigned Boolean; 253typedef const struct __CFString * CFStringRef; 254typedef const struct __CFAllocator * CFAllocatorRef; 255extern const CFAllocatorRef kCFAllocatorDefault; 256extern const CFAllocatorRef kCFAllocatorSystemDefault; 257extern const CFAllocatorRef kCFAllocatorMalloc; 258extern const CFAllocatorRef kCFAllocatorMallocZone; 259extern const CFAllocatorRef kCFAllocatorNull; 260extern const CFAllocatorRef kCFAllocatorUseContext; 261CFStringRef CFStringCreateWithBytesNoCopy(CFAllocatorRef alloc, const uint8_t *bytes, CFIndex numBytes, CFStringEncoding encoding, Boolean externalFormat, CFAllocatorRef contentsDeallocator); 262 263void DellocWithCFStringCreate1(CFAllocatorRef alloc) { 264 unsigned int *ptr = 0; 265 OSStatus st = 0; 266 UInt32 length; 267 void *bytes; 268 char * x; 269 st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &bytes); 270 if (st == noErr) { 271 CFStringRef userStr = CFStringCreateWithBytesNoCopy(alloc, bytes, length, 5, 0, kCFAllocatorDefault); // expected-warning{{Deallocator doesn't match the allocator:}} 272 CFRelease(userStr); 273 } 274} 275 276void DellocWithCFStringCreate2(CFAllocatorRef alloc) { 277 unsigned int *ptr = 0; 278 OSStatus st = 0; 279 UInt32 length; 280 void *bytes; 281 char * x; 282 st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &bytes); 283 if (st == noErr) { 284 CFStringRef userStr = CFStringCreateWithBytesNoCopy(alloc, bytes, length, 5, 0, kCFAllocatorNull); // expected-warning{{Allocated data is not released}} 285 CFRelease(userStr); 286 } 287} 288 289void DellocWithCFStringCreate3(CFAllocatorRef alloc) { 290 unsigned int *ptr = 0; 291 OSStatus st = 0; 292 UInt32 length; 293 void *bytes; 294 char * x; 295 st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &bytes); 296 if (st == noErr) { 297 CFStringRef userStr = CFStringCreateWithBytesNoCopy(alloc, bytes, length, 5, 0, kCFAllocatorUseContext); 298 CFRelease(userStr); 299 } 300} 301 302void DellocWithCFStringCreate4(CFAllocatorRef alloc) { 303 unsigned int *ptr = 0; 304 OSStatus st = 0; 305 UInt32 length; 306 void *bytes; 307 char * x; 308 st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &bytes); 309 if (st == noErr) { 310 CFStringRef userStr = CFStringCreateWithBytesNoCopy(alloc, bytes, length, 5, 0, 0); // expected-warning{{Deallocator doesn't match the allocator:}} 311 CFRelease(userStr); 312 } 313} 314 315static CFAllocatorRef gKeychainDeallocator = 0; 316 317static CFAllocatorRef GetKeychainDeallocator() { 318 return gKeychainDeallocator; 319} 320 321CFStringRef DellocWithCFStringCreate5(CFAllocatorRef alloc) { 322 unsigned int *ptr = 0; 323 OSStatus st = 0; 324 UInt32 length; 325 void *bytes; 326 char * x; 327 st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &bytes); 328 if (st == noErr) { 329 return CFStringCreateWithBytesNoCopy(alloc, bytes, length, 5, 0, GetKeychainDeallocator()); // no-warning 330 } 331 return 0; 332} 333 334void radar10508828() { 335 UInt32 pwdLen = 0; 336 void* pwdBytes = 0; 337 OSStatus rc = SecKeychainFindGenericPassword(0, 3, "foo", 3, "bar", &pwdLen, &pwdBytes, 0); 338#pragma unused(rc) 339 if (pwdBytes) 340 SecKeychainItemFreeContent(0, pwdBytes); 341} 342 343void radar10508828_20092614() { 344 UInt32 pwdLen = 0; 345 void* pwdBytes = 0; 346 OSStatus rc = SecKeychainFindGenericPassword(0, 3, "foo", 3, "bar", &pwdLen, &pwdBytes, 0); 347 SecKeychainItemFreeContent(0, pwdBytes); 348} 349 350//Example from bug 10797. 351__inline__ static 352const char *__WBASLLevelString(int level) { 353 return "foo"; 354} 355 356static int *bug10798(int *p, int columns, int prevRow) { 357 int *row = 0; 358 row = p + prevRow * columns; 359 prevRow += 2; 360 do { 361 ++prevRow; 362 row+=columns; 363 } while(10 >= row[1]); 364 return row; 365} 366 367// Test inter-procedural behaviour. 368 369void my_FreeParam(void *attrList, void* X) { 370 SecKeychainItemFreeContent(attrList, X); 371} 372 373void *my_AllocateReturn(OSStatus *st) { 374 unsigned int *ptr = 0; 375 UInt32 length; 376 void *outData; 377 *st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData); 378 return outData; 379} 380 381OSStatus my_Allocate_Param(void** password, UInt32* passwordLength) { 382 OSStatus err; 383 SecKeychainItemRef item; 384 err = SecKeychainFindGenericPassword(0, 3, "xx", 3, "xx", 385 passwordLength, password, &item); 386 return err; 387} 388 389void allocAndFree1() { 390 unsigned int *ptr = 0; 391 OSStatus st = 0; 392 UInt32 length; 393 void *outData; 394 st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData); 395 if (st == noErr) 396 my_FreeParam(ptr, outData); 397} 398 399void consumeChar(char); 400 401void allocNoFree2(int x) { 402 OSStatus st = 0; 403 void *outData = my_AllocateReturn(&st); 404 if (x) { 405 consumeChar(*(char*)outData); // expected-warning{{Allocated data is not released:}} 406 return; 407 } else { 408 consumeChar(*(char*)outData); 409 } 410 return; 411} 412 413void allocAndFree2(void *attrList) { 414 OSStatus st = 0; 415 void *outData = my_AllocateReturn(&st); 416 if (st == noErr) 417 my_FreeParam(attrList, outData); 418} 419 420void allocNoFree3() { 421 UInt32 length = 32; 422 void *outData; 423 void *outData2; 424 OSStatus st = my_Allocate_Param(&outData, &length); // expected-warning{{Allocated data is not released}} 425 st = my_Allocate_Param(&outData2, &length); // expected-warning{{Allocated data is not released}} 426} 427 428void allocAndFree3(void *attrList) { 429 UInt32 length = 32; 430 void *outData; 431 OSStatus st = my_Allocate_Param(&outData, &length); 432 if (st == noErr) 433 SecKeychainItemFreeContent(attrList, outData); 434} 435 436typedef struct AuthorizationValue { 437 int length; 438 void *data; 439} AuthorizationValue; 440typedef struct AuthorizationCallback { 441 OSStatus (*SetContextVal)(AuthorizationValue *inValue); 442} AuthorizationCallback; 443static AuthorizationCallback cb; 444int radar_19196494() { 445 @autoreleasepool { 446 AuthorizationValue login_password = {}; 447 UInt32 passwordLength; 448 void *passwordData = 0; 449 OSStatus err = SecKeychainFindGenericPassword(0, 0, "", 0, "", (UInt32 *)&login_password.length, (void**)&login_password.data, 0); 450 cb.SetContextVal(&login_password); 451 if (err == noErr) { 452 SecKeychainItemFreeContent(0, login_password.data); 453 } 454 } 455 return 0; 456} 457int radar_19196494_v2() { 458 @autoreleasepool { 459 AuthorizationValue login_password = {}; 460 OSStatus err = SecKeychainFindGenericPassword(0, 0, "", 0, "", (UInt32 *)&login_password.length, (void**)&login_password.data, 0); 461 if (!login_password.data) return 0; 462 cb.SetContextVal(&login_password); 463 if (err == noErr) { 464 SecKeychainItemFreeContent(0, login_password.data); 465 } 466 } 467 return 0; 468} 469