CFRelease crash in iOS10

Below is my code that worked fine until 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; } 

This method worked fine until iOS 9.x, but today, when I upgraded my Xcode to 8 and started on the iOS 10 device. The application gets broken into
CFRelease (PublicKey) .

Before the failure, there is a log below the console.

Failed to load Objective-C class information. This will significantly reduce the quality of available type information.

enter image description here

Could not solve the problem exactly.

When I turned on Zombie and reproduced the crash. Below is the log from the console.

*** - [Not A Type release]: message sent to the released instance 0x170225880

Thanks in advance.

I have a problem. there is an internal method encodedData = [self encryptData: dataToEncrypt withKeyRef: publicKey];

when the SecKeyRef object is freed.

But I wonder how it worked before 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; } 
0
objective-c ios10 xcode8 core-foundation seckeyref
source share
1 answer

In encryptData:withKeyRef: you have unbalanced CFRelease at the end of the method. Nothing in this method has survived keyRef , but you release it. Delete this call.

Why hadn't he crashed before? Because something else probably kept it before, maybe a cache, maybe something else. Cocoa does not make promises that excessive release will immediately (or ever) result in a crash. You have entered undefined behavior.

It is very disturbing that the static analyzer does not detect this. I would open an error report (bugreport.apple.com). You have a very clear violation of memory management, and the analyzer must catch it.

+4
source share

All Articles