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