keychainAPI.m revision f7ce52b0995efd65d51a3359939c09022a23e04c
1// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.osx.KeychainAPI %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) // 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.
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 nt 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.
146OSStatus testSecKeychainFindGenericPassword(UInt32* passwordLength) {
147  OSStatus err;
148  SecKeychainItemRef item;
149  void *password;
150  err = SecKeychainFindGenericPassword(0, 3, "xx", 3, "xx",
151                                       passwordLength, &password, &item);
152  if (err == noErr && password) {
153    SecKeychainItemFreeContent(0, password);
154  }
155  return err;
156}
157
158int apiMismatch(SecKeychainItemRef itemRef, 
159         SecKeychainAttributeInfo *info,
160         SecItemClass *itemClass) {
161  OSStatus st = 0;
162  SecKeychainAttributeList *attrList;
163  UInt32 length;
164  void *outData;
165  
166  st = SecKeychainItemCopyAttributesAndData(itemRef, info, itemClass, 
167                                            &attrList, &length, &outData); 
168  if (st == noErr)
169    SecKeychainItemFreeContent(attrList, outData); // expected-warning{{Allocator doesn't match the deallocator}}
170  return 0;
171}
172
173int ErrorCodesFromDifferentAPISDoNotInterfere(SecKeychainItemRef itemRef, 
174                                              SecKeychainAttributeInfo *info,
175                                              SecItemClass *itemClass) {
176  unsigned int *ptr = 0;
177  OSStatus st = 0;
178  UInt32 length;
179  void *outData;
180  OSStatus st2 = 0;
181  SecKeychainAttributeList *attrList;
182  UInt32 length2;
183  void *outData2;
184
185  st2 = SecKeychainItemCopyAttributesAndData(itemRef, info, itemClass, 
186                                             &attrList, &length2, &outData2);
187  st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData);  
188  if (st == noErr) {
189    SecKeychainItemFreeContent(ptr, outData);
190    if (st2 == noErr) {
191      SecKeychainItemFreeAttributesAndData(attrList, outData2);
192    }
193  } 
194  return 0; // expected-warning{{Allocated data is not released: missing a call to 'SecKeychainItemFreeAttributesAndData'}}
195}
196
197int foo(CFTypeRef keychainOrArray, SecProtocolType protocol, 
198        SecAuthenticationType authenticationType, SecKeychainItemRef *itemRef) {
199  unsigned int *ptr = 0;
200  OSStatus st = 0;
201
202  UInt32 length;
203  void *outData[5];
204
205  st = SecKeychainFindInternetPassword(keychainOrArray, 
206                                       16, "server", 16, "domain", 16, "account",
207                                       16, "path", 222, protocol, authenticationType,
208                                       &length, &(outData[3]), itemRef);
209  if (length == 5) {
210    if (st == noErr)
211      SecKeychainItemFreeContent(ptr, outData[3]);
212  }
213  if (length) { // expected-warning{{Allocated data is not released: missing a call to 'SecKeychainItemFreeContent'.}}
214    length++;
215  }
216  return 0;
217}// no-warning
218