iOS10中的CFRelease崩溃

时间:2016-10-05 11:57:25

标签: objective-c ios10 xcode8 core-foundation seckeyref

下面是我的代码,过去一直工作到iOS 9。

- (NSData *)encryptWithDataPublicKey:(NSString*)data keyTag:(NSString*)tag
{  

    SecKeyRef publicKey = NULL;                                           
    NSData *publicTag = [NSData dataWithBytes:[tag UTF8String] length:[tag length]];

    NSMutableDictionary *queryPublicKey =
    [[NSMutableDictionary alloc] init];

    [queryPublicKey setObject:(__bridge id)kSecClassKey forKey:(__bridge id)kSecClass];  

    [queryPublicKey setObject:publicTag forKey:(__bridge id)kSecAttrApplicationTag];

    [queryPublicKey setObject:(__bridge id)kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];

    [queryPublicKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecReturnRef];

    OSStatus status = SecItemCopyMatching
    ((__bridge CFDictionaryRef)queryPublicKey, (CFTypeRef *)&publicKey);

    NSData *encodedData = nil;  

    if (status == noErr && publicKey) {  
        NSData *dataToEncrypt = [data dataUsingEncoding:NSUTF8StringEncoding];  
        encodedData = [self encryptData:dataToEncrypt withKeyRef:publicKey];  
        CFRelease(publicKey);  
    }  
    return encodedData;  
}

此方法在iOS 9.x之前一直运行良好,但今天我已将我的XCode更新为8并在iOS 10设备上运行。应用程序正在崩溃 的 CFRelease(公钥)

在崩溃之前是来自控制台的日志。

  

无法加载任何Objective-C类信息。这将   显着降低可用类型信息的质量

enter image description here

无法准确解决问题。

当我启用Zombie时,重现崩溃。以下是来自控制台的日志。

*** - [Not A Type release]:发送到解除分配的实例的消息0x170225880

提前致谢。

我得到了这个问题。 有一个内部方法encodedData = [self encryptData:dataToEncrypt withKeyRef:publicKey];

SecKeyRef对象被释放。

但我想知道这是如何工作到iOS9 ???????

-(NSData *)encryptData:(NSData *)data withKeyRef:(SecKeyRef) keyRef{
    const uint8_t *srcbuf = (const uint8_t *)[data bytes];
    size_t srclen = (size_t)data.length;

    size_t block_size = SecKeyGetBlockSize(keyRef) * sizeof(uint8_t);
    void *outbuf = malloc(block_size);
    size_t src_block_size = block_size - 11;

    NSMutableData *ret = [[NSMutableData alloc] init];
    for(int idx=0; idx<srclen; idx+=src_block_size){
        size_t data_len = srclen - idx;
        if(data_len > src_block_size){
            data_len = src_block_size;
        }

        size_t outlen = block_size;
        OSStatus status = noErr;
        status = SecKeyEncrypt(keyRef,
                               kSecPaddingPKCS1,
                               srcbuf + idx,
                               data_len,
                               outbuf,
                               &outlen
                               );
        if (status != 0) {
            ret = nil;
            break;
        }else{
            [ret appendBytes:outbuf length:outlen];
        }
    }

    free(outbuf);
    CFRelease(keyRef);
    return ret;
}

1 个答案:

答案 0 :(得分:4)

encryptData:withKeyRef:中,您在方法结束时遇到了不平衡CFRelease。该方法中没有任何内容保留keyRef,但您将其释放。删除该电话。

为什么它之前没有崩溃?因为其他东西之前可能会在内部保留它,可能是缓存,可能是其他东西。 Cocoa没有承诺过度释放会立即(或曾经)导致崩溃。你处于未定义的行为。

但是,非常令人痛苦的是,静态分析仪没有检测到这一点。我会打开一个关于它的bug报告(bugreport.apple.com)。你有一个非常清楚的内存管理违规,分析器应该抓住它。