GLKTextureLoader -textureWithCGImage:options:queue:completionHandler: malloc error

2.2k views Asked by At

I am using a GLKTextureLoader instance to asynchronously load a texture:

NSDictionary *options = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] 
                                                    forKey:GLKTextureLoaderOriginBottomLeft];
GLKTextureLoader *asyncLoader = [[GLKTextureLoader alloc] initWithSharegroup:sharegroup];
[asyncLoader textureWithCGImage:image
                        options:options
                          queue:NULL
              completionHandler:^(GLKTextureInfo *textureInfo, NSError *outError) {
                  if (outError) [ISDebugger logError:outError inMethod:_cmd];
                  GLuint textureName = [textureInfo name];
                  if (completionHandler) completionHandler(textureName);
              }];

The first time this code is run, it works fine. However the second time around, I get a malloc: *** error for object 0xa0cb3c0: pointer being freed was not allocated warning in the console. The backtrace appears to show that the error occurs in the GLKTextureLoader's own worker thread:

* thread #16: tid = 0x3003, 0x91a32c91 libsystem_c.dylib`malloc_error_break, stop reason = breakpoint 1.1
    frame #0: 0x91a32c91 libsystem_c.dylib`malloc_error_break
    frame #1: 0x91a32e07 libsystem_c.dylib`free + 358
    frame #2: 0x011f5003 CoreGraphics`image_provider_finalize + 29
    frame #3: 0x01b144b3 CoreFoundation`CFRelease + 291
    frame #4: 0x0118d96c CoreGraphics`CGImageBlockSetRelease + 76
    frame #5: 0x0154646c GLKit`-[GLKTexture dealloc] + 65
    frame #6: 0x02184e3d libobjc.A.dylib`_objc_rootRelease + 47
    frame #7: 0x01549da0 GLKit`+[GLKTextureLoader commonTextureWithCGImage:options:error:lock:eaglContext:] + 277
    frame #8: 0x0154b77e GLKit`__71-[GLKTextureLoader textureWithCGImage:options:queue:completionHandler:]_block_invoke_0 + 140
    frame #9: 0x0232b330 libdispatch.dylib`_dispatch_call_block_and_release + 15
    frame #10: 0x0232c439 libdispatch.dylib`_dispatch_worker_thread2 + 302
    frame #11: 0x919dfb24 libsystem_c.dylib`_pthread_wqthread + 346

Obviously enough, it seems that the texture loader is over-releasing something. What am I doing wrong here?


Update:

The image being passed into the method is obtained something like this:

NSString *bundlePath = [[NSBundle mainBundle] bundlePath];
NSString *imagePath = [bundlePath stringByAppendingPathComponent:imageFilename];
UIImage *uiImage = [UIImage imageWithContentsOfFile:imagePath];
CGImageRef image = [uiImage CGImage];

Changing the image generation to this stopped the error from occurring:

UIImage *uiImage = [UIImage imageNamed:imageFilename];
CGImageRef image = [uiImage CGImage];

So now I suppose the question is why? I understand that +imageNamed: includes some caching behaviour, but why should that affect this code?


Update 2:

This the same when the image is created using [UIImage imageWithData:imageData] (crash occurs). It seems that the only [UIImage imageNamed:imageName] is working. Any ideas why?

1

There are 1 answers

1
john.k.doe On

you are using an async method to process this item. it's likely not the asyncLoader that's performing the release, but something else.

if you declared image as a UIImage locally, called this asyncLoader to run, and then immediately exit your current stackFrame (i.e. the current method that makes this call), the UIImage you passed will likely have been released prior to you doing something with it in the asyncLoader. (the same thing will happen if the UIImage were passed in, and but is released in a calling stack-frame ... or if it is weak and the thing that holds a ref to it removes it before the asyncLoader runs).

i would suggest making an strong @property out of image (and set it to nil in your viewController's viewDidUnload), and then this problem should go away.