Home > Net >  Swift takeRetainedValue() and takeUnretainedValue() both EXC_BAD_ACCESS
Swift takeRetainedValue() and takeUnretainedValue() both EXC_BAD_ACCESS

Time:09-23

I have objc function that return SecIdentityRef

  (SecIdentityRef)getSecIdentity {
NSString *resourcePath = [[NSBundle mainBundle] pathForResource:@"cert1" ofType:@"p12"];
NSData *p12Data = [NSData dataWithContentsOfFile:resourcePath];
NSMutableDictionary * options = [[NSMutableDictionary alloc] init];

[options setObject:@"123456" forKey:(id)kSecImportExportPassphrase];

CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);

OSStatus securityError = SecPKCS12Import((CFDataRef) p12Data,
                                         (CFDictionaryRef)options, &items);

if (securityError == noErr && CFArrayGetCount(items) > 0) {
    CFDictionaryRef identityDict = CFArrayGetValueAtIndex(items, 0);
    SecIdentityRef identityApp =
    (SecIdentityRef)CFDictionaryGetValue(identityDict,
                                         kSecImportItemIdentity);
    CFRelease(items);
    return identityApp;
}

CFRelease(items);
return NULL;
}

I import class with this function in bridging header, then use it in swift code

let test = Certificate.getSecIdentity()
let secIdentity = test.takeUnretainedValue()

From Certificate.getSecIdentity() returns Unmanaged<SecIdentityRef> with correct (?) SecIdentity inside.

enter image description here

On test.takeUnretainedValue() (and test.takeRetainedValue()) I receive Thread 1: EXC_BAD_ACCESS (code=1, address=0x2d13e474f3e0)

What I do wrong? How can I get SecIdentity?

CodePudding user response:

When you retrieve an element from (i believe) any core foundation collection, the collection functions follows the Get-Rule. It means that you don't own the element until you explicitly retain it. Thus in this part of your code:

SecIdentityRef identityApp = (SecIdentityRef)CFDictionaryGetValue(identityDict, kSecImportItemIdentity);
CFRelease(items);

You essentially release both items and identityApp and return a dangling pointer (a dangling core foundation reference to be precise). Just retain the instance of SecIdentityRef before your release the items array like that:

CFRetain(identityApp);
CFRelease(items);
return identityApp;

P.S. since your function may return NULL, you better make the result nullable, especially when working with Swift, so it knows the result is an optional value:

  (nullable SecIdentityRef)getSecIdentity

P.P.S. you also may want to rewrite you code in Swift directly, since it supports work with SecCertificate

  • Related