1 // RUN: %clang_cc1 -analyze -analyzer-checker=osx.SecKeychainAPI %s -verify 2 3 // Fake typedefs. 4 typedef unsigned int OSStatus; 5 typedef unsigned int SecKeychainAttributeList; 6 typedef unsigned int SecKeychainItemRef; 7 typedef unsigned int SecItemClass; 8 typedef unsigned int UInt32; 9 typedef unsigned int CFTypeRef; 10 typedef unsigned int UInt16; 11 typedef unsigned int SecProtocolType; 12 typedef unsigned int SecAuthenticationType; 13 typedef unsigned int SecKeychainAttributeInfo; 14 enum { 15 noErr = 0, 16 GenericError = 1 17 }; 18 19 // Functions that allocate data. 20 OSStatus SecKeychainItemCopyContent ( 21 SecKeychainItemRef itemRef, 22 SecItemClass *itemClass, 23 SecKeychainAttributeList *attrList, 24 UInt32 *length, 25 void **outData 26 ); 27 OSStatus 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 ); 37 OSStatus 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 ); 54 OSStatus 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. 64 OSStatus SecKeychainItemFreeContent ( 65 SecKeychainAttributeList *attrList, 66 void *data 67 ); 68 OSStatus SecKeychainItemFreeAttributesAndData ( 69 SecKeychainAttributeList *attrList, 70 void *data 71 ); 72 73 void 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) // expected-warning{{Allocated data is not released: missing a call to 'SecKeychainItemFreeContent'.}} 80 SecKeychainItemFreeContent(ptr, outData); // expected-warning{{Call to free data when error was returned during allocation.}} 81 } 82 83 // If null is passed in, the data is not allocated, so no need for the matching free. 84 void 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 93 void 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 void 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. 113 void 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. 122 void fooOnlyFreeParam(void *attrList, void* X) { 123 SecKeychainItemFreeContent(attrList, X); 124 }// no-warning 125 126 // If we are returning the value, do not report. 127 void* 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 nt have to be deleted. 137 OSStatus 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. 147 OSStatus 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 168 int 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 183 int 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 207 int 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 229 void free(void *ptr); 230 void 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. 241 typedef char uint8_t; 242 typedef signed long CFIndex; 243 typedef UInt32 CFStringEncoding; 244 typedef unsigned Boolean; 245 typedef const struct __CFString * CFStringRef; 246 typedef const struct __CFAllocator * CFAllocatorRef; 247 extern const CFAllocatorRef kCFAllocatorDefault; 248 extern const CFAllocatorRef kCFAllocatorSystemDefault; 249 extern const CFAllocatorRef kCFAllocatorMalloc; 250 extern const CFAllocatorRef kCFAllocatorMallocZone; 251 extern const CFAllocatorRef kCFAllocatorNull; 252 extern const CFAllocatorRef kCFAllocatorUseContext; 253 CFStringRef CFStringCreateWithBytesNoCopy(CFAllocatorRef alloc, const uint8_t *bytes, CFIndex numBytes, CFStringEncoding encoding, Boolean externalFormat, CFAllocatorRef contentsDeallocator); 254 extern void CFRelease(CFStringRef cf); 255 256 void 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 269 void 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 282 void 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 295 void 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 308 //Example from bug 10797. 309 __inline__ static 310 const char *__WBASLLevelString(int level) { 311 return "foo"; 312 } 313 314 static int *bug10798(int *p, int columns, int prevRow) { 315 int *row = 0; 316 row = p + prevRow * columns; 317 prevRow += 2; 318 do { 319 ++prevRow; 320 row+=columns; 321 } while(10 >= row[1]); 322 return row; 323 } 324