Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<ul> <li>You receive the keychain object from a CF-style function with <code>Copy</code> in its name. Therefore it has a +1 reference count, and you have the responsibility of explicitly releasing it when you're done using it. It is never released by your sample code, so it's leaking. The keychain object is never used in the code you posted, thus it can be eliminated entirely.</li> <li>In the first solution, you pass <code>attributeQuery</code> (a local variable) with a simple <code>__bridge</code> cast, which is not a good a idea; ARC may release it prematurely from under you. You should use <code>__bridge_retained</code> (or <code>CFBridgingRetain</code>) to convert it into CF country with a +1 retain count (and explicitly release it later).</li> <li>In the second solution, you use <code>__bridge_retained</code>, but you do not release the result, which explains the leak.</li> <li>The return value of <code>SecItemCopyMatching</code> is zero if the call was successful. You should not compare only against <code>errSecItemNotFound</code>; there can be any number of other reasons for a failed query.</li> </ul> <p>Updated code:</p> <pre><code>NSMutableDictionary *attributeQuery = [NSMutableDictionary dictionary]; [attributeQuery setObject:(id)kSecClassIdentity forKey:(__bridge id)kSecClass]; [attributeQuery setObject:(id)kCFBooleanTrue forKey:(__bridge id)kSecReturnRef]; [attributeQuery setObject:(id)kSecMatchLimitAll forKey:(__bridge id)kSecMatchLimit]; CFTypeRef attrResult = NULL; CFDictionaryRef cfquery = (CFDictionaryRef)CFBridgingRetain(attributeQuery); OSStatus status = SecItemCopyMatching(cfquery, &amp;cfresult); CFRelease(cfquery); if (status == errSecSuccess) { NSArray *attributeResult = CFBridgingRelease(cfresult); [attributeResult enumerateObjectsUsingBlock:^(id value, NSUInteger idx, BOOL *stop) { OSStatus status; SecCertificateRef cert = NULL; SecIdentityRef identity = CFBridgingRetain(value); status = SecIdentityCopyCertificate(identity, &amp;cert); CFRelease(identity); if (!status) { ... CFRelease(cert); }]; } </code></pre> <p>I find the Core Foundation/Cocoa bridging casts a little hard to read, so I personally find it cleaner to skip the Cocoa level and create the query dictionary directly on the CF level like this:</p> <pre><code>CFMutableDictionaryRef cfquery = CFDictionaryCreateMutable(NULL, 0, &amp;kCFTypeDictionaryKeyCallBacks, &amp;kCFTypeDictionaryValueCallBacks); CFDictionarySetValue(cfquery, kSecClass, kSecClassIdentity); CFDictionarySetValue(cfquery, kSecReturnRef, kCFBoolenTrue); CFDictionarySetValue(cfquery, kSecMatchLimit, kSecMatchLimitAll); CFArrayRef cfidentities = NULL; OSStatus status = SecItemCopyMatching((CFDictionaryRef)cfquery, (CFTypeRef *)&amp;cfidentities); CFRelease(cfquery); if (status == errSecSuccess) { NSArray *identities = CFBridgingRelease(cfidentities); for (id value in identities) { SecCertificateRef cfcertificate; SecIdentityRef cfidentity = (SecIdentityRef)CFBridgingRetain(value); status = SecIdentityCopyCertificate(cfidentity, &amp;cfcertificate); if (status == errSecSuccess) { // ... CFRelease(cfcertificate); } } } </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload