EndyVelvet
EndyVelvet

Reputation: 441

Reference-counted object is used after it is released

Doing code analysis of the project and get the message "Reference-counted object is used after it is released" on the line [defaults setObject: deviceUuid forKey: @ "deviceUuid"];

I watched this topic Obj-C, Reference-counted object is used after it is released? But the solution is not found. ARC disabled.

// Get the users Device Model, Display Name, Unique ID, Token & Version Number
UIDevice *dev = [UIDevice currentDevice];
NSString *deviceUuid;
if ([dev respondsToSelector:@selector(uniqueIdentifier)])
    deviceUuid = dev.uniqueIdentifier;
else {
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    id uuid = [defaults objectForKey:@"deviceUuid"];
    if (uuid)
        deviceUuid = (NSString *)uuid;
    else {
        CFStringRef cfUuid = CFUUIDCreateString(NULL, CFUUIDCreate(NULL));
        deviceUuid = (NSString *)cfUuid;
        CFRelease(cfUuid);
        [defaults setObject:deviceUuid forKey:@"deviceUuid"];
    }
}

Please help find the cause.

Upvotes: 1

Views: 1795

Answers (2)

Steven Fisher
Steven Fisher

Reputation: 44856

The problems is here:

    CFStringRef cfUuid = CFUUIDCreateString(NULL, CFUUIDCreate(NULL));
    deviceUuid = (NSString *)cfUuid;
    CFRelease(cfUuid);
    [defaults setObject:deviceUuid forKey:@"deviceUuid"];

Let's go through what this actually does:

    CFStringRef cfUuid = CFUUIDCreateString(NULL, CFUUIDCreate(NULL));

A CFUUID is created (and leaked). A CFStringRef is created and assigned to cfUuid. (Note: The name cfUuid implies that cfUuid is a CFUUIDRef. Of course, it isn't; it's a CFStringRef.)

    deviceUuid = (NSString *)cfUuid;

That same CFStringRef is type cast and assigned to deviceUuid. This is not a new instance of NSString or CFStringRef, it's just a typecast of the same instance.

    CFRelease(cfUuid);

You release the CFStringRef. Since the NSString points to the same object, you also release it.

    [defaults setObject:deviceUuid forKey:@"deviceUuid"];

And here, you use the typecasted object, which was released before.

THe simplest fix to the stale pointer is this:

    CFStringRef cfUuid = CFUUIDCreateString(NULL, CFUUIDCreate(NULL));
    deviceUuid = (NSString *)cfUuid;
    [defaults setObject:deviceUuid forKey:@"deviceUuid"];
    CFRelease(cfUuid);

But this code is dangerous, and you already know why: deviceUuid is also invalid. But this isn't obvious, so you can trip on it later. Also, it doesn't fix the CFUUID leak.

To fix the CFStringRef leak, you could use this:

    deviceUuid = (NSString *)CFUUIDCreateString(NULL, CFUUIDCreate(NULL));
    [defaults setObject:deviceUuid forKey:@"deviceUuid"];
    [deviceUuid autorelease]; // or release, if you don't need it in code not
                              // included in your post

However, this still doesn't fix the CFUUID leak.

    CFUUIDRef cfuuid = CFUUIDCreate(NULL);
    deviceUuid = (NSString *)CFUUIDCreateString(NULL, cfuuid);
    CFRelease(cfuuid);
    [defaults setObject:deviceUuid forKey:@"deviceUuid"];
    [deviceUuid autorelease]; // or release, if you don't need it in code not
                              // included in your post

Upvotes: 5

Richard J. Ross III
Richard J. Ross III

Reputation: 55533

The problem is Here:

CFRelease(cfUuid); 

You shouldn't release that, you should release deviceUuid when you are done with that.

Upvotes: 1

Related Questions