ibireme / YYKit

A collection of iOS components.
MIT License
13.99k stars 3.69k forks source link

SecItemCopyMatching函数内存泄漏问题 #521

Open lengain opened 5 years ago

lengain commented 5 years ago
+ (YYKeychainItem *)selectOneItem:(YYKeychainItem *)item error:(NSError **)error {
    if (!item.service || !item.account) {
        if (error) *error = [YYKeychain errorWithCode:errSecParam];
        return nil;
    }

    NSMutableDictionary *query = [item dic];
    query[(__bridge id)kSecMatchLimit] = (__bridge id)kSecMatchLimitOne;
    query[(__bridge id)kSecReturnAttributes] = @YES;
    query[(__bridge id)kSecReturnData] = @YES;

    OSStatus status;
    CFTypeRef result = NULL;
    status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &result);//这里存在内存泄漏
    if (status != errSecSuccess) {
        if (error) *error = [[self class] errorWithCode:status];
        return nil;
    }
    if (!result) return nil;

    NSDictionary *dic = nil;
    if (CFGetTypeID(result) == CFDictionaryGetTypeID()) {
        dic = (__bridge NSDictionary *)(result);
    } else if (CFGetTypeID(result) == CFArrayGetTypeID()){
        dic = [(__bridge NSArray *)(result) firstObject];
        if (![dic isKindOfClass:[NSDictionary class]]) dic = nil;
    }
    if (!dic.count) return nil;
    return [[YYKeychainItem alloc] initWithDic:dic];
}

SecItemCopyMatching在使用时会使得参数CFDictionaryRef引用计数加1,因此需要手动释放

CFDictionaryRef retainQuery =(CFDictionaryRef)CFBridgingRetain(query);
status = SecItemCopyMatching(retainQuery, &result);
CFRelease(retainQuery);