// 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() { 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() { 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() { 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() { 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() { 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) { // TODO: We do not report a warning here since the symbol is no longer live, but it's not marked as dead. 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() { 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() { 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() { 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() { 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() { 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() { 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() { @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; }