1// RUN: %clang_cc1 -analyze -analyzer-checker=osx.SecKeychainAPI %s -verify
2
3// Fake typedefs.
4typedef unsigned int OSStatus;
5typedef unsigned int SecKeychainAttributeList;
6typedef unsigned int SecKeychainItemRef;
7typedef unsigned int SecItemClass;
8typedef unsigned int UInt32;
9typedef unsigned int CFTypeRef;
10typedef unsigned int UInt16;
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); // expected-warning{{Only call free if a valid (non-NULL) buffer was returned}}
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
104void 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.
113void 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.
122void fooOnlyFreeParam(void *attrList, void* X) {
123    SecKeychainItemFreeContent(attrList, X); 
124}// no-warning
125
126// If we are returning the value, do not report.
127void* 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 not have to be deleted.
137OSStatus 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.
147OSStatus 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
168int 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
183int 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
207int 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
229void free(void *ptr);
230void 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.
241typedef char uint8_t;
242typedef signed long CFIndex;
243typedef UInt32 CFStringEncoding;
244typedef unsigned Boolean;
245typedef const struct __CFString * CFStringRef;
246typedef const struct __CFAllocator * CFAllocatorRef;
247extern const CFAllocatorRef kCFAllocatorDefault;
248extern const CFAllocatorRef kCFAllocatorSystemDefault;
249extern const CFAllocatorRef kCFAllocatorMalloc;
250extern const CFAllocatorRef kCFAllocatorMallocZone;
251extern const CFAllocatorRef kCFAllocatorNull;
252extern const CFAllocatorRef kCFAllocatorUseContext;
253CFStringRef CFStringCreateWithBytesNoCopy(CFAllocatorRef alloc, const uint8_t *bytes, CFIndex numBytes, CFStringEncoding encoding, Boolean externalFormat, CFAllocatorRef contentsDeallocator);
254extern void CFRelease(CFStringRef cf);
255
256void 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
269void 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
282void 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
295void 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
308static CFAllocatorRef gKeychainDeallocator = 0;
309
310static CFAllocatorRef GetKeychainDeallocator() {  
311  return gKeychainDeallocator;
312}
313
314CFStringRef DellocWithCFStringCreate5(CFAllocatorRef alloc) {
315  unsigned int *ptr = 0;
316  OSStatus st = 0;
317  UInt32 length;
318  void *bytes;
319  char * x;
320  st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &bytes);
321  if (st == noErr) {
322    return CFStringCreateWithBytesNoCopy(alloc, bytes, length, 5, 0, GetKeychainDeallocator()); // no-warning
323  }
324  return 0;
325}
326
327void radar10508828() {
328  UInt32 pwdLen = 0;
329  void*  pwdBytes = 0;
330  OSStatus rc = SecKeychainFindGenericPassword(0, 3, "foo", 3, "bar", &pwdLen, &pwdBytes, 0);
331#pragma unused(rc)
332  if (pwdBytes)
333    SecKeychainItemFreeContent(0, pwdBytes);
334}
335
336void radar10508828_2() {
337  UInt32 pwdLen = 0;
338  void*  pwdBytes = 0;
339  OSStatus rc = SecKeychainFindGenericPassword(0, 3, "foo", 3, "bar", &pwdLen, &pwdBytes, 0);
340  SecKeychainItemFreeContent(0, pwdBytes); // expected-warning {{Only call free if a valid (non-NULL) buffer was returned}}
341}
342
343//Example from bug 10797.
344__inline__ static
345const char *__WBASLLevelString(int level) {
346  return "foo";
347}
348
349static int *bug10798(int *p, int columns, int prevRow) {
350  int *row = 0;
351  row = p + prevRow * columns;
352  prevRow += 2;
353  do {
354    ++prevRow;
355    row+=columns;
356  } while(10 >= row[1]);
357  return row;
358}
359
360// Test inter-procedural behaviour.
361
362void my_FreeParam(void *attrList, void* X) {
363    SecKeychainItemFreeContent(attrList, X); 
364}
365
366void *my_AllocateReturn(OSStatus *st) {
367  unsigned int *ptr = 0;
368  UInt32 length;
369  void *outData;
370  *st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData);
371  return outData;
372}
373
374OSStatus my_Allocate_Param(void** password, UInt32* passwordLength) {
375  OSStatus err;
376  SecKeychainItemRef item;
377  err = SecKeychainFindGenericPassword(0, 3, "xx", 3, "xx",
378                                       passwordLength, password, &item);
379  return err;
380}
381
382void allocAndFree1() {
383    unsigned int *ptr = 0;
384    OSStatus st = 0;
385    UInt32 length;
386    void *outData;
387    st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData);
388    if (st == noErr)
389      my_FreeParam(ptr, outData);
390}
391
392void consumeChar(char);
393
394void allocNoFree2(int x) {
395    OSStatus st = 0;
396    void *outData = my_AllocateReturn(&st); 
397    if (x) {
398      consumeChar(*(char*)outData); // expected-warning{{Allocated data is not released:}}
399      return;
400    } else {
401      consumeChar(*(char*)outData);
402    }
403    return;
404}
405
406void allocAndFree2(void *attrList) {
407    OSStatus st = 0;
408    void *outData = my_AllocateReturn(&st);
409    if (st == noErr)
410      my_FreeParam(attrList, outData);
411}
412
413void allocNoFree3() {
414    UInt32 length = 32;
415    void *outData;    
416    void *outData2;
417    OSStatus st = my_Allocate_Param(&outData, &length); // expected-warning{{Allocated data is not released}}
418    st = my_Allocate_Param(&outData2, &length); // expected-warning{{Allocated data is not released}}
419}
420
421void allocAndFree3(void *attrList) {
422    UInt32 length = 32;
423    void *outData;
424    OSStatus st = my_Allocate_Param(&outData, &length); 
425    if (st == noErr)
426      SecKeychainItemFreeContent(attrList, outData);
427}
428
429