Search code examples
objective-cxcodecocoaautomatic-ref-countingclang-static-analyzer

Why does the static analyzer show this bridged NSNumber to be leaking under ARC?


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?


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.