0

以下は、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(publicKey)でクラッシュしています。

以下はクラッシュする前のコンソールからのログです。

Objective-C クラス情報を読み込めませんでした。これにより、利用可能な型情報の品質が大幅に低下します

ここに画像の説明を入力

問題を正確に取得できませんでした。

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;
}
4

1 に答える 1

5

メソッドの最後に不均衡encryptData:withKeyRef:があります。CFReleaseそのメソッドには何も保持されていませんkeyRefが、解放します。その呼び出しを削除します。

なぜ以前にクラッシュしなかったのですか?他の何かが以前に内部的にそれを保持していた可能性が高いため、おそらくキャッシュ、おそらく他の何かです。Cocoa は、過剰なリリースがすぐに (または絶対に) クラッシュにつながることを約束しません。あなたは未定義の行動に陥っていました。

ただし、静的アナライザーがこれを検出しないのは非常に残念です。それに関するバグレポートを開きます (bugreport.apple.com)。非常に明確なメモリ管理違反があり、アナライザーはそれをキャッチする必要があります。

于 2016-10-06T14:21:40.553 に答える