| // RUN: %clang_analyze_cc1 -analyzer-checker=osx.SecKeychainAPI -fblocks %s -verify | 
 |  | 
 | #include "Inputs/system-header-simulator-objc.h" | 
 |  | 
 | // Fake typedefs. | 
 | typedef unsigned int OSStatus; | 
 | typedef unsigned int SecKeychainAttributeList; | 
 | typedef unsigned int SecKeychainItemRef; | 
 | typedef unsigned int SecItemClass; | 
 | typedef unsigned int UInt32; | 
 | typedef unsigned int SecProtocolType; | 
 | typedef unsigned int SecAuthenticationType; | 
 | typedef unsigned int SecKeychainAttributeInfo; | 
 | enum { | 
 |   noErr                      = 0, | 
 |   GenericError               = 1 | 
 | }; | 
 |  | 
 | // Functions that allocate data. | 
 | OSStatus SecKeychainItemCopyContent ( | 
 |     SecKeychainItemRef itemRef, | 
 |     SecItemClass *itemClass, | 
 |     SecKeychainAttributeList *attrList, | 
 |     UInt32 *length, | 
 |     void **outData | 
 | ); | 
 | OSStatus SecKeychainFindGenericPassword ( | 
 |     CFTypeRef keychainOrArray, | 
 |     UInt32 serviceNameLength, | 
 |     const char *serviceName, | 
 |     UInt32 accountNameLength, | 
 |     const char *accountName, | 
 |     UInt32 *passwordLength, | 
 |     void **passwordData, | 
 |     SecKeychainItemRef *itemRef | 
 | ); | 
 | OSStatus SecKeychainFindInternetPassword ( | 
 |     CFTypeRef keychainOrArray, | 
 |     UInt32 serverNameLength, | 
 |     const char *serverName, | 
 |     UInt32 securityDomainLength, | 
 |     const char *securityDomain, | 
 |     UInt32 accountNameLength, | 
 |     const char *accountName, | 
 |     UInt32 pathLength, | 
 |     const char *path, | 
 |     UInt16 port, | 
 |     SecProtocolType protocol, | 
 |     SecAuthenticationType authenticationType, | 
 |     UInt32 *passwordLength, | 
 |     void **passwordData, | 
 |     SecKeychainItemRef *itemRef | 
 | ); | 
 | OSStatus SecKeychainItemCopyAttributesAndData ( | 
 |    SecKeychainItemRef itemRef, | 
 |    SecKeychainAttributeInfo *info, | 
 |    SecItemClass *itemClass, | 
 |    SecKeychainAttributeList **attrList, | 
 |    UInt32 *length, | 
 |    void **outData | 
 | ); | 
 |  | 
 | // Functions which free data. | 
 | OSStatus SecKeychainItemFreeContent ( | 
 |     SecKeychainAttributeList *attrList, | 
 |     void *data | 
 | ); | 
 | OSStatus SecKeychainItemFreeAttributesAndData ( | 
 |    SecKeychainAttributeList *attrList, | 
 |    void *data | 
 | ); | 
 |  | 
 | void errRetVal(void) { | 
 |   unsigned int *ptr = 0; | 
 |   OSStatus st = 0; | 
 |   UInt32 length; | 
 |   void *outData; | 
 |   st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData); | 
 |   if (st == GenericError) | 
 |     SecKeychainItemFreeContent(ptr, outData); | 
 | } // expected-warning{{Allocated data is not released: missing a call to 'SecKeychainItemFreeContent'}} | 
 |  | 
 | // If null is passed in, the data is not allocated, so no need for the matching free. | 
 | void fooDoNotReportNull(void) { | 
 |     unsigned int *ptr = 0; | 
 |     OSStatus st = 0; | 
 |     UInt32 *length = 0; | 
 |     void **outData = 0; | 
 |     SecKeychainItemCopyContent(2, ptr, ptr, 0, 0); | 
 |     SecKeychainItemCopyContent(2, ptr, ptr, length, outData); | 
 | }// no-warning | 
 |  | 
 | void doubleAlloc(void) { | 
 |     unsigned int *ptr = 0; | 
 |     OSStatus st = 0; | 
 |     UInt32 length; | 
 |     void *outData; | 
 |     st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData); | 
 |     st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData); // expected-warning {{Allocated data should be released before another call to the allocator:}} | 
 |     if (st == noErr) | 
 |       SecKeychainItemFreeContent(ptr, outData); | 
 | } | 
 |  | 
 | // Do not warn if undefined value is passed to a function. | 
 | void fooOnlyFreeUndef(void) { | 
 |   unsigned int *ptr = 0; | 
 |   OSStatus st = 0; | 
 |   UInt32 length; | 
 |   void *outData; | 
 |   SecKeychainItemFreeContent(ptr, outData); | 
 | }// no-warning | 
 |  | 
 | // Do not warn if the address is a parameter in the enclosing function. | 
 | void fooOnlyFreeParam(void *attrList, void* X) { | 
 |     SecKeychainItemFreeContent(attrList, X);  | 
 | }// no-warning | 
 |  | 
 | // If we are returning the value, do not report. | 
 | void* returnContent(void) { | 
 |   unsigned int *ptr = 0; | 
 |   OSStatus st = 0; | 
 |   UInt32 length; | 
 |   void *outData; | 
 |   st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData); | 
 |   return outData; | 
 | } // no-warning | 
 |  | 
 | // Password was passed in as an argument and does not have to be deleted. | 
 | OSStatus getPasswordAndItem(void** password, UInt32* passwordLength) { | 
 |   OSStatus err; | 
 |   SecKeychainItemRef item; | 
 |   err = SecKeychainFindGenericPassword(0, 3, "xx", 3, "xx", | 
 |                                        passwordLength, password, &item); | 
 |   return err; | 
 | } // no-warning | 
 |  | 
 | // Make sure we do not report an error if we call free only if password != 0. | 
 | // Also, do not report double allocation if first allocation returned an error. | 
 | OSStatus testSecKeychainFindGenericPassword(UInt32* passwordLength, | 
 |                         CFTypeRef keychainOrArray, SecProtocolType protocol,  | 
 |                         SecAuthenticationType authenticationType) { | 
 |   OSStatus err; | 
 |   SecKeychainItemRef item; | 
 |   void *password; | 
 |   err = SecKeychainFindGenericPassword(0, 3, "xx", 3, "xx", | 
 |                                        passwordLength, &password, &item); | 
 |   if( err == GenericError ) { | 
 |     err = SecKeychainFindInternetPassword(keychainOrArray,  | 
 |                                   16, "server", 16, "domain", 16, "account", | 
 |                                   16, "path", 222, protocol, authenticationType, | 
 |                                   passwordLength, &(password), 0); | 
 |   } | 
 |  | 
 |   if (err == noErr && password) { | 
 |     SecKeychainItemFreeContent(0, password); | 
 |   } | 
 |   return err; | 
 | } | 
 |  | 
 | int apiMismatch(SecKeychainItemRef itemRef,  | 
 |          SecKeychainAttributeInfo *info, | 
 |          SecItemClass *itemClass) { | 
 |   OSStatus st = 0; | 
 |   SecKeychainAttributeList *attrList; | 
 |   UInt32 length; | 
 |   void *outData; | 
 |    | 
 |   st = SecKeychainItemCopyAttributesAndData(itemRef, info, itemClass,  | 
 |                                             &attrList, &length, &outData);  | 
 |   if (st == noErr) | 
 |     SecKeychainItemFreeContent(attrList, outData); // expected-warning{{Deallocator doesn't match the allocator}} | 
 |   return 0; | 
 | } | 
 |  | 
 | int ErrorCodesFromDifferentAPISDoNotInterfere(SecKeychainItemRef itemRef,  | 
 |                                               SecKeychainAttributeInfo *info, | 
 |                                               SecItemClass *itemClass) { | 
 |   unsigned int *ptr = 0; | 
 |   OSStatus st = 0; | 
 |   UInt32 length; | 
 |   void *outData; | 
 |   OSStatus st2 = 0; | 
 |   SecKeychainAttributeList *attrList; | 
 |   UInt32 length2; | 
 |   void *outData2; | 
 |  | 
 |   st2 = SecKeychainItemCopyAttributesAndData(itemRef, info, itemClass,  | 
 |                                              &attrList, &length2, &outData2); | 
 |   st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData);   | 
 |   if (st == noErr) { | 
 |     SecKeychainItemFreeContent(ptr, outData); | 
 |     if (st2 == noErr) { | 
 |       SecKeychainItemFreeAttributesAndData(attrList, outData2); | 
 |     } | 
 |   }  | 
 |   return 0; // expected-warning{{Allocated data is not released: missing a call to 'SecKeychainItemFreeAttributesAndData'}} | 
 | } | 
 |  | 
 | int foo(CFTypeRef keychainOrArray, SecProtocolType protocol,  | 
 |         SecAuthenticationType authenticationType, SecKeychainItemRef *itemRef) { | 
 |   unsigned int *ptr = 0; | 
 |   OSStatus st = 0; | 
 |  | 
 |   UInt32 length; | 
 |   void *outData[5]; | 
 |  | 
 |   st = SecKeychainFindInternetPassword(keychainOrArray,  | 
 |                                        16, "server", 16, "domain", 16, "account", | 
 |                                        16, "path", 222, protocol, authenticationType, | 
 |                                        &length, &(outData[3]), itemRef); | 
 |   if (length == 5) { | 
 |     if (st == noErr) | 
 |       SecKeychainItemFreeContent(ptr, outData[3]); | 
 |   } | 
 |   if (length) { // expected-warning{{Allocated data is not released: missing a call to 'SecKeychainItemFreeContent'}} | 
 |     length++; | 
 |   } | 
 |   return 0; | 
 | } | 
 |  | 
 | int testErrorCodeAsLHS(CFTypeRef keychainOrArray, SecProtocolType protocol, | 
 |         SecAuthenticationType authenticationType, SecKeychainItemRef *itemRef) { | 
 |   unsigned int *ptr = 0; | 
 |   OSStatus st = 0; | 
 |   UInt32 length; | 
 |   void *outData; | 
 |   st = SecKeychainFindInternetPassword(keychainOrArray, | 
 |                                        16, "server", 16, "domain", 16, "account", | 
 |                                        16, "path", 222, protocol, authenticationType, | 
 |                                        &length, &outData, itemRef); | 
 |   if (noErr == st) | 
 |     SecKeychainItemFreeContent(ptr, outData); | 
 |  | 
 |   return 0; | 
 | } | 
 |  | 
 | void free(void *ptr); | 
 | void deallocateWithFree(void) { | 
 |     unsigned int *ptr = 0; | 
 |     OSStatus st = 0; | 
 |     UInt32 length; | 
 |     void *outData; | 
 |     st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData); | 
 |     if (st == noErr) | 
 |       free(outData); // expected-warning{{Deallocator doesn't match the allocator: 'SecKeychainItemFreeContent' should be used}} | 
 | } | 
 |  | 
 | // Typesdefs for CFStringCreateWithBytesNoCopy. | 
 | typedef char uint8_t; | 
 | typedef signed long CFIndex; | 
 | typedef UInt32 CFStringEncoding; | 
 | typedef unsigned Boolean; | 
 | typedef const struct __CFString * CFStringRef; | 
 | typedef const struct __CFAllocator * CFAllocatorRef; | 
 | extern const CFAllocatorRef kCFAllocatorDefault; | 
 | extern const CFAllocatorRef kCFAllocatorSystemDefault; | 
 | extern const CFAllocatorRef kCFAllocatorMalloc; | 
 | extern const CFAllocatorRef kCFAllocatorMallocZone; | 
 | extern const CFAllocatorRef kCFAllocatorNull; | 
 | extern const CFAllocatorRef kCFAllocatorUseContext; | 
 | CFStringRef CFStringCreateWithBytesNoCopy(CFAllocatorRef alloc, const uint8_t *bytes, CFIndex numBytes, CFStringEncoding encoding, Boolean externalFormat, CFAllocatorRef contentsDeallocator); | 
 |  | 
 | void DellocWithCFStringCreate1(CFAllocatorRef alloc) { | 
 |   unsigned int *ptr = 0; | 
 |   OSStatus st = 0; | 
 |   UInt32 length; | 
 |   void *bytes; | 
 |   char * x; | 
 |   st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &bytes); | 
 |   if (st == noErr) { | 
 |     CFStringRef userStr = CFStringCreateWithBytesNoCopy(alloc, bytes, length, 5, 0, kCFAllocatorDefault); // expected-warning{{Deallocator doesn't match the allocator:}}  | 
 |     CFRelease(userStr); | 
 |   } | 
 | } | 
 |  | 
 | void DellocWithCFStringCreate2(CFAllocatorRef alloc) { | 
 |   unsigned int *ptr = 0; | 
 |   OSStatus st = 0; | 
 |   UInt32 length; | 
 |   void *bytes; | 
 |   char * x; | 
 |   st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &bytes); | 
 |   if (st == noErr) { | 
 |     CFStringRef userStr = CFStringCreateWithBytesNoCopy(alloc, bytes, length, 5, 0, kCFAllocatorNull); // expected-warning{{Allocated data is not released}} | 
 |     CFRelease(userStr);  | 
 |   } | 
 | } | 
 |  | 
 | void DellocWithCFStringCreate3(CFAllocatorRef alloc) { | 
 |   unsigned int *ptr = 0; | 
 |   OSStatus st = 0; | 
 |   UInt32 length; | 
 |   void *bytes; | 
 |   char * x; | 
 |   st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &bytes); | 
 |   if (st == noErr) { | 
 |     CFStringRef userStr = CFStringCreateWithBytesNoCopy(alloc, bytes, length, 5, 0, kCFAllocatorUseContext); | 
 |     CFRelease(userStr); | 
 |   } | 
 | } | 
 |  | 
 | void DellocWithCFStringCreate4(CFAllocatorRef alloc) { | 
 |   unsigned int *ptr = 0; | 
 |   OSStatus st = 0; | 
 |   UInt32 length; | 
 |   void *bytes; | 
 |   char * x; | 
 |   st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &bytes); | 
 |   if (st == noErr) { | 
 |     CFStringRef userStr = CFStringCreateWithBytesNoCopy(alloc, bytes, length, 5, 0, 0); // expected-warning{{Deallocator doesn't match the allocator:}}  | 
 |     CFRelease(userStr); | 
 |   } | 
 | } | 
 |  | 
 | static CFAllocatorRef gKeychainDeallocator = 0; | 
 |  | 
 | static CFAllocatorRef GetKeychainDeallocator(void) {   | 
 |   return gKeychainDeallocator; | 
 | } | 
 |  | 
 | CFStringRef DellocWithCFStringCreate5(CFAllocatorRef alloc) { | 
 |   unsigned int *ptr = 0; | 
 |   OSStatus st = 0; | 
 |   UInt32 length; | 
 |   void *bytes; | 
 |   char * x; | 
 |   st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &bytes); | 
 |   if (st == noErr) { | 
 |     return CFStringCreateWithBytesNoCopy(alloc, bytes, length, 5, 0, GetKeychainDeallocator()); // no-warning | 
 |   } | 
 |   return 0; | 
 | } | 
 |  | 
 | void radar10508828(void) { | 
 |   UInt32 pwdLen = 0; | 
 |   void*  pwdBytes = 0; | 
 |   OSStatus rc = SecKeychainFindGenericPassword(0, 3, "foo", 3, "bar", &pwdLen, &pwdBytes, 0); | 
 | #pragma unused(rc) | 
 |   if (pwdBytes) | 
 |     SecKeychainItemFreeContent(0, pwdBytes); | 
 | } | 
 |  | 
 | void radar10508828_20092614(void) { | 
 |   UInt32 pwdLen = 0; | 
 |   void*  pwdBytes = 0; | 
 |   OSStatus rc = SecKeychainFindGenericPassword(0, 3, "foo", 3, "bar", &pwdLen, &pwdBytes, 0); | 
 |   SecKeychainItemFreeContent(0, pwdBytes); | 
 | } | 
 |  | 
 | //Example from bug 10797. | 
 | __inline__ static | 
 | const char *__WBASLLevelString(int level) { | 
 |   return "foo"; | 
 | } | 
 |  | 
 | static int *bug10798(int *p, int columns, int prevRow) { | 
 |   int *row = 0; | 
 |   row = p + prevRow * columns; | 
 |   prevRow += 2; | 
 |   do { | 
 |     ++prevRow; | 
 |     row+=columns; | 
 |   } while(10 >= row[1]); | 
 |   return row; | 
 | } | 
 |  | 
 | // Test inter-procedural behaviour. | 
 |  | 
 | void my_FreeParam(void *attrList, void* X) { | 
 |     SecKeychainItemFreeContent(attrList, X);  | 
 | } | 
 |  | 
 | void *my_AllocateReturn(OSStatus *st) { | 
 |   unsigned int *ptr = 0; | 
 |   UInt32 length; | 
 |   void *outData; | 
 |   *st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData); | 
 |   return outData; | 
 | } | 
 |  | 
 | OSStatus my_Allocate_Param(void** password, UInt32* passwordLength) { | 
 |   OSStatus err; | 
 |   SecKeychainItemRef item; | 
 |   err = SecKeychainFindGenericPassword(0, 3, "xx", 3, "xx", | 
 |                                        passwordLength, password, &item); | 
 |   return err; | 
 | } | 
 |  | 
 | void allocAndFree1(void) { | 
 |     unsigned int *ptr = 0; | 
 |     OSStatus st = 0; | 
 |     UInt32 length; | 
 |     void *outData; | 
 |     st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData); | 
 |     if (st == noErr) | 
 |       my_FreeParam(ptr, outData); | 
 | } | 
 |  | 
 | void consumeChar(char); | 
 |  | 
 | void allocNoFree2(int x) { | 
 |     OSStatus st = 0; | 
 |     void *outData = my_AllocateReturn(&st);  | 
 |     if (x) { | 
 |       consumeChar(*(char*)outData); // expected-warning{{Allocated data is not released:}} | 
 |       return; | 
 |     } else { | 
 |       consumeChar(*(char*)outData); | 
 |     } | 
 |     return; | 
 | } | 
 |  | 
 | void allocAndFree2(void *attrList) { | 
 |     OSStatus st = 0; | 
 |     void *outData = my_AllocateReturn(&st); | 
 |     if (st == noErr) | 
 |       my_FreeParam(attrList, outData); | 
 | } | 
 |  | 
 | void allocNoFree3(void) { | 
 |     UInt32 length = 32; | 
 |     void *outData;     | 
 |     void *outData2; | 
 |     OSStatus st = my_Allocate_Param(&outData, &length); // expected-warning{{Allocated data is not released}} | 
 |     st = my_Allocate_Param(&outData2, &length); // expected-warning{{Allocated data is not released}} | 
 | } | 
 |  | 
 | void allocAndFree3(void *attrList) { | 
 |     UInt32 length = 32; | 
 |     void *outData; | 
 |     OSStatus st = my_Allocate_Param(&outData, &length);  | 
 |     if (st == noErr) | 
 |       SecKeychainItemFreeContent(attrList, outData); | 
 | } | 
 |  | 
 | typedef struct AuthorizationValue { | 
 |     int length; | 
 |     void *data; | 
 | } AuthorizationValue; | 
 | typedef struct AuthorizationCallback { | 
 |     OSStatus (*SetContextVal)(AuthorizationValue *inValue); | 
 | } AuthorizationCallback; | 
 | static AuthorizationCallback cb; | 
 | int radar_19196494(void) { | 
 |   @autoreleasepool { | 
 |     AuthorizationValue login_password = {}; | 
 |     UInt32 passwordLength; | 
 |     void *passwordData = 0; | 
 |     OSStatus err = SecKeychainFindGenericPassword(0, 0, "", 0, "", (UInt32 *)&login_password.length, (void**)&login_password.data, 0); | 
 |     cb.SetContextVal(&login_password); | 
 |     if (err == noErr) { | 
 |       SecKeychainItemFreeContent(0, login_password.data); | 
 |     } | 
 |   } | 
 |   return 0; | 
 | } | 
 | int radar_19196494_v2(void) { | 
 |   @autoreleasepool { | 
 |     AuthorizationValue login_password = {}; | 
 |     OSStatus err = SecKeychainFindGenericPassword(0, 0, "", 0, "", (UInt32 *)&login_password.length, (void**)&login_password.data, 0); | 
 |     if (!login_password.data) return 0; | 
 |     cb.SetContextVal(&login_password); | 
 |     if (err == noErr) { | 
 |       SecKeychainItemFreeContent(0, login_password.data); | 
 |     } | 
 |   } | 
 |   return 0; | 
 | } |