Question

When running the Clang Static Analyzer against code that I've converted to use ARC, it's reporting the NSNumber in this block of code to be a leak:

NSNumber *temporaryNumber = [NSNumber numberWithFloat:0.85];
CFNumberRef compressionQuality = CFBridgingRetain(temporaryNumber);

CFDictionarySetValue(snapshotMetaAndOpts, kCGImageDestinationLossyCompressionQuality, compressionQuality);
CFRelease(compressionQuality);

The analyzer indicates that the NSNumber created and stored into temporaryNumber ends up with a +1 retain count after all this, and thus leaks. I know that I could just as easily do

CFDictionarySetValue(snapshotMetaAndOpts, kCGImageDestinationLossyCompressionQuality, (__bridge CFNumberRef)[NSNumber numberWithFloat:0.85]);

but I'm still trying to understand the exact actions of bridging in ARC, so I'm trying to puzzle out the above. The actual analyzer output is as follows:

Visual depiction of static analyzer results

The way I read CFBridgingRetain() and __bridge_retained is that they transfer ownership of an ARC-managed NSObject to Core Foundation by increasing the retain count by 1. I balance this with a corresponding CFRelease(). I would the expect the NSNumber to be created as an autoreleased object, and therefore be completely balanced on the ARC side.

Similarly, if I do the following using a plain __bridge cast:

NSNumber *temporaryNumber = [NSNumber numberWithFloat:0.85];
CFNumberRef compressionQuality = (__bridge CFNumberRef)temporaryNumber;
CFDictionarySetValue(snapshotMetaAndOpts, kCGImageDestinationLossyCompressionQuality, compressionQuality);
CFRelease(compressionQuality);

the static analyzer gives this a clean bill of health.

Am I misreading something in the way that objects are toll-free bridged, or is this a bug in the static analyzer?

Was it helpful?

Solution

EDIT: This is an analyzer bug. I have the latest build of the standalone analyzer on my machine and there is no warning. I verified against a build with the current shipping analyzer and got the same results as you. Looks like its already good to go.

What version of Xcode are you using? I just tested the following.

int main(int argc, char *argv[])
{
    @autoreleasepool 
    {
        CFMutableDictionaryRef dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);

        NSNumber *temporaryNumber = [NSNumber numberWithFloat:0.85];
        CFNumberRef compressionQuality = CFBridgingRetain(temporaryNumber);

        CFDictionarySetValue(dict, CFSTR("Test"), compressionQuality);
        CFRelease(compressionQuality);

        CFRelease(dict);
    }
}

This works as expected and provides no analyzer warnings. This is on the latest 4.2 on 10.7, using the iOS SDK.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top