blob: 4fc48c066f9dff0f4ef4ecf365333a89f48c65b7 [file] [log] [blame]
// RUN: %clang_cc1 -analyze -analyzer-checker=osx.SecKeychainAPI %s -verify
// 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 CFTypeRef;
typedef unsigned int UInt16;
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{{Only call free if a valid (non-NULL) buffer was returned}}
} // 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);
}
void fooOnlyFree() {
unsigned int *ptr = 0;
OSStatus st = 0;
UInt32 length;
void *outData = &length;
SecKeychainItemFreeContent(ptr, outData);// expected-warning{{Trying to free data which has not been allocated}}
}
// 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) { // expected-warning{{Allocated data is not released: missing a call to 'SecKeychainItemFreeContent'}}
length++;
}
return 0;
}// no-warning
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);
extern void CFRelease(CFStringRef cf);
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_2() {
UInt32 pwdLen = 0;
void* pwdBytes = 0;
OSStatus rc = SecKeychainFindGenericPassword(0, 3, "foo", 3, "bar", &pwdLen, &pwdBytes, 0);
SecKeychainItemFreeContent(0, pwdBytes); // expected-warning {{Only call free if a valid (non-NULL) buffer was returned}}
}
//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);
}