Tim R.
Tim R.

Reputation: 1650

Analyzer claiming an object was released when it wasn't

I am getting a static analysis error in this code which doesn't make any sense to me. The error is:

Reference-counted object is used after it is released

This is glue code to allow for PNG loading in a game originally written in C++.

int pngLoad(const char *filename, pngInfo *info, int format, GLuint *textureName)
{
    char fullPath[Engine::Settings::MaxPath];
    strcpy(fullPath, filename);
    appendAppBundlePath(fullPath);

    NSString *path = [NSString stringWithCString:fullPath encoding:NSUTF8StringEncoding];
    NSData *data = [[NSData alloc] initWithContentsOfFile:path];
    UIImage *image = [[UIImage alloc] initWithData:data];
    [data release];

    Texture2D *loadedTex = [Texture2D alloc];

    // ##### Analyzer claims the object is released here: #####
    [loadedTex initWithImage:image format:format];

    int didLoad;

    // ##### Error is here: #####
    if (loadedTex.contentSize.width == 0 || loadedTex.contentSize.height == 0)
    {
        didLoad = 0;
    }
    else
    {
        didLoad = 1;

        *textureName = loadedTex.name;

        // return texture info
        info->ScaleFactor = loadedTex.scaleFactor;
        info->Width = (float)image.size.width / (float)info->ScaleFactor;
        info->Height = (float)image.size.height / (float)info->ScaleFactor;
        info->Alpha = 1;
        info->PaddedWidth = loadedTex.pixelsWide;
        info->PaddedHeight = loadedTex.pixelsHigh;
    }

    [loadedTex release];
    [image release];

    return didLoad;
}

If I use Texture2D *loadedTex = [[Texture2D alloc] retain]; this warning is removed, but then an warning that I've leaked an object comes up, so something is seriously weird here.

initWithImage:format: used to contain a [self release] which shouldn't have been there, which I removed when I found this warning. However, even after a full clean and rebuild, I still get the warning. Am I doing something else wrong? Is something not getting properly cleaned up by the Clean command in Xcode?

Upvotes: 0

Views: 74

Answers (2)

Christian Stieber
Christian Stieber

Reputation: 12496

The analyzer may be right, at least in a general way.

Texture2D *loadedTex = [Texture2D alloc];
[loadedTex initWithImage:image format:format];

In general, "init" might actually discard the object passed in and return a different one. Whether or not this is the case for "Texture2D" is something I don't know, but if the analyzer is going for the general case then it is right.

You should be able to work around that by using

Texture2D *loadedTex = [Texture2D alloc];
loadedTex=[loadedTex initWithImage:image format:format];

Or by simply combining the two calls, as it is done in most Objective-C examples.

Upvotes: 2

Martin R
Martin R

Reputation: 539965

You should always combine the alloc and initXXX call when creating objects, in this case

Texture2D *loadedTex = [[Texture2D alloc] initWithImage:image format:format];

An init method need not return the same object it was called with, it is allowed to return a different object.

In this case your result from loadedTex = [Texture2D alloc] would be released and initWithImage would return a different object (which you discard).

Upvotes: 0

Related Questions