i found memory leak on SecItemCopyMatching. After investigate on SF i was found solution:
__block NSString *certificateName = nil;
SecKeychainRef keychain;
SecKeychainCopyDefault(&keychain);
NSMutableDictionary *attributeQuery = [NSMutableDictionary dictionary];
[attributeQuery setObject: (id) kSecClassIdentity forKey:(__bridge_transfer id) kSecClass];
[attributeQuery setObject: (id) kCFBooleanTrue forKey:(__bridge_transfer id) kSecReturnRef];
[attributeQuery setObject: (id) kSecMatchLimitAll forKey:(__bridge_transfer id) kSecMatchLimit];
CFTypeRef attrResult = NULL;
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef) attributeQuery,(CFTypeRef *) &attrResult);<------- here is a leak according Instruments
if (status != errSecItemNotFound) {
NSArray *attributeResult = (__bridge_transfer NSArray *)attrResult;
[attributeResult enumerateObjectsUsingBlock:^(id identityFromArray, NSUInteger idx, BOOL *stop) {
OSStatus status;
SecCertificateRef cert = NULL;
status = SecIdentityCopyCertificate((__bridge SecIdentityRef)identityFromArray, &cert);
if (!status)
{
or another solution:
NSMutableDictionary *attributeQuery = [NSMutableDictionary dictionary];
[attributeQuery setObject: (id) kSecClassIdentity forKey:(__bridge_transfer id) kSecClass];
[attributeQuery setObject: (id) kCFBooleanTrue forKey:(__bridge_transfer id) kSecReturnRef];
[attributeQuery setObject: (id) kSecMatchLimitAll forKey:(__bridge_transfer id) kSecMatchLimit];
CFTypeRef attrResult = NULL;
CFDictionaryRef cfquery = (__bridge_retained CFDictionaryRef)attributeQuery;
OSStatus status = SecItemCopyMatching(cfquery,(CFTypeRef *) &attrResult);<------- here is a leak according Instruments
if (status != errSecItemNotFound) {
NSArray *attributeResult = (__bridge_transfer NSArray *)attrResult;
[attributeResult enumerateObjectsUsingBlock:^(id identityFromArray, NSUInteger idx, BOOL *stop) {
OSStatus status;
SecCertificateRef cert = NULL;
status = SecIdentityCopyCertificate((__bridge SecIdentityRef)identityFromArray, &cert);
if (!status)
{
char *nameBuf = NULL;
CFStringRef nameRef = NULL;
OSStatus statusNew = SecCertificateInferLabel(cert, &nameRef);
.....
CFRelease(cfquery)
But both of them still do leak for me.
Any another ideas
Copy
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.attributeQuery
(a local variable) with a simple__bridge
cast, which is not a good a idea; ARC may release it prematurely from under you. You should use__bridge_retained
(orCFBridgingRetain
) to convert it into CF country with a +1 retain count (and explicitly release it later).__bridge_retained
, but you do not release the result, which explains the leak.SecItemCopyMatching
is zero if the call was successful. You should not compare only againsterrSecItemNotFound
; there can be any number of other reasons for a failed query.Updated code:
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: