views:

5035

answers:

8

Hello, i got this message from the debugger:

Pixture(1257,0xa0610500) malloc: *** error for object 0x21a8000: pointer being freed was not allocated

*** set a breakpoint in malloc_error_break to debug

so i did a bit of tracing and got:

(gdb) shell malloc_history 1257 0x21a8000

ALLOC 0x2196a00-0x21a89ff [size=73728]: thread_a0610500 |start | main | UIApplicationMain | GSEventRun | GSEventRunModal | CFRunLoopRunInMode | CFRunLoopRunSpecific | __CFRunLoopDoObservers | CA::Transaction::observer_callback(__CFRunLoopObserver*, unsigned long, void*) | CA::Transaction::commit() | CA::Context::commit_transaction(CA::Transaction*) | CALayerDisplayIfNeeded | -[CALayer _display] | CABackingStoreUpdate | backing_callback(CGContext*, void*) | -[CALayer drawInContext:] | -[UIView(CALayerDelegate) drawLayer:inContext:] | -[AvatarView drawRect:] | -[AvatarView overlayPNG:] | +[UIImageUtility createMaskOf:] | UIGraphicsGetImageFromCurrentImageContext | CGBitmapContextCreateImage | create_bitmap_data_provider | malloc | malloc_zone_malloc

and i really can't understand what i am doing wrong. here's the code of the [UIImageUtility createMaskOf:] function:

+ (UIImage *)createMaskOf:(UIImage *)source {
    CGRect rect = CGRectMake(0, 0, source.size.width, source.size.height);
    UIGraphicsBeginImageContext(CGSizeMake(source.size.width, source.size.height));
    CGContextRef context = UIGraphicsGetCurrentContext();

    CGContextTranslateCTM(context, 0, source.size.height);
    CGContextScaleCTM(context, 1.0, -1.0);

    UIImage *original = [self createGrayCopy:source];

    CGContextRef context2 = CGBitmapContextCreate(NULL, source.size.width, source.size.height, 8, 4 * source.size.width, 
                  CGColorSpaceCreateDeviceRGB(), kCGImageAlphaNoneSkipLast);
    CGContextDrawImage(context2, CGRectMake(0, 0, source.size.width, source.size.height), original.CGImage);
    CGImageRef unmasked = CGBitmapContextCreateImage(context2);

    const float myMaskingColorsFrameColor[6] = { 1,256,1,256,1,256 };
    CGImageRef mask = CGImageCreateWithMaskingColors(unmasked, myMaskingColorsFrameColor);

    CGContextSetRGBFillColor (context, 256,256,256, 1);
    CGContextFillRect(context, rect);
    CGContextDrawImage(context, rect, mask);

    UIImage *whiteMasked = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();

    return whiteMasked;
}

the other custom function called before that is the following:

- (UIImage *)overlayPNG:(SinglePart *)sp {
    NSLog([sp description]);
    // Rect and context setup
    CGRect rect = CGRectMake(0, 0, sp.image.size.width, sp.image.size.height);
    NSLog(@"%f x %f", sp.image.size.width, sp.image.size.height);

    // Create an image of a color filled rectangle
    UIImage *baseColor = nil;
    if (sp.hasOwnColor) {
         baseColor = [UIImageUtility imageWithRect:rect ofColor:sp.color];
    } else {
     SinglePart *facePart = [editingAvatar.face.partList objectAtIndex:0];
     baseColor = [UIImageUtility imageWithRect:rect ofColor:facePart.color];
    }

    // Crete the mask of the layer
    UIImage *mask = [UIImageUtility createMaskOf:sp.image];
    mask = [UIImageUtility createGrayCopy:mask];

    // Create a new context for merging the overlay and a mask of the layer
    UIGraphicsBeginImageContext(CGSizeMake(sp.image.size.width, sp.image.size.height));
    CGContextRef context2 = UIGraphicsGetCurrentContext(); 

    // Adjust the coordinate system so that the origin 
    // is in the lower left corner of the view and the 
    // y axis points up 
    CGContextTranslateCTM(context2, 0, sp.image.size.height); 
    CGContextScaleCTM(context2, 1.0, -1.0); 

    // Create masked overlay color layer
    CGImageRef MaskedImage = CGImageCreateWithMask (baseColor.CGImage, mask.CGImage);

    // Draw the base color layer
    CGContextDrawImage(context2, rect, MaskedImage);

    // Get the result of the masking
    UIImage* overlayMasked = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    UIGraphicsBeginImageContext(CGSizeMake(sp.image.size.width, sp.image.size.height));
    CGContextRef context = UIGraphicsGetCurrentContext();

    // Adjust the coordinate system so that the origin 
    // is in the lower left corner of the view and the 
    // y axis points up 
    CGContextTranslateCTM(context, 0, sp.image.size.height);
    CGContextScaleCTM(context, 1.0, -1.0);

    // Get the result of the blending of the masked overlay and the base image
    CGContextDrawImage(context, rect, overlayMasked.CGImage);

    // Set the blend mode for the next drawn image
    CGContextSetBlendMode(context, kCGBlendModeOverlay);

    // Component image drawn
    CGContextDrawImage(context, rect, sp.image.CGImage);

    UIImage* blendedImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    CGImageRelease(MaskedImage);

    return blendedImage;
}
+7  A: 

It looks like you have a corrupted memory bug, and it is probably not in this code. Corrupted memory bugs are my second most-fun bugs, partially because they are often non-deterministic, and the symptoms (aka the crashes) usually happen long after the actual bug hit.

There are two main types of memory bugs:

  1. Allocating more than you free.
  2. Freeing more than you allocate.

In this case it looks like you're freeing too much, which is the easier case to see (b/c it can crash earlier) but the harder to track down.

Here is a strategy you can use to help find an extra deallocations:

  • Turn off some of your deallocations.
  • See if the crash still occurs.

Ideally, you can find one single deallocation command which, when removed, will allow your code to work correctly. It might be useful to try a binary search approach, if that is practical for your codebase. If it's a large codebase, hopefully you're using version control and you can try to focus on the recent diff's.

Keep in mind that deallocations can be invoked in several different ways here. Most likely, you're calling release and autorelease on objects. It's also possible you might be explicitly calling dealloc (which is usually a mistake, though). And of course you might even be explicitly calling free directly.

Once you've gotten rid of the extra deallocations, it's a good idea to also check for memory leaks (aka extra allocations). You can do this by using Instruments and other tools. A good place to start is by reading Finding Memory Leaks in the iPhone development guide.

Added: It's also a good idea to set a pointer to nil right after you've released it and are done using it. This way, if you call [objectPtr release]; later, it won't do anything.

(PS Btw, my #1 most-fun bug type is memory corruption in mutlithreaded code. I had one of those once in a multi-million line code base.)

Tyler
ItWhat you say is probabl true, also because this message i posted doesn't correspond to application crashes, it just writes on the debug console (and slow the application) in a random fashon, sometimes it gives me 2 of them, sometimes 4, sometimes a lot, sometimes even no messages... Anyway, i'll try to follow your instructions and see if i can get anywhere. If i don't maybe I can post a bit more code and you can help me in finding the problem?
w4nderlust
You can post, but no promises about detailed line-by-line debugging here. Stackoverflow is more about either big picture questions or quick-but-specific questions, as opposed to time-consuming-and-detailed questions, since this last kind is the least useful for other people. Also it's a lot of work to do for a stranger for free ;)
Tyler
I removed every single release call in all the classes that are loaded before the first of that messages cames out. I got no result at all. I'll show you the previous function calling the one i've shown, hoping that the problem is there. (By the way i have to say a funny thing: the application haven't had this error since i updated to snow leopard and xcode 3.2... without changing a line this erorr came out)
w4nderlust
This is unlikely, but it's vaguely possible that you found a bug in the api. From my experience, 9 times out of 10 when I thought I had an api bug, it was still my fault, though.
Tyler
I was stuck with m problem, but i decided to go forward implementing something new in my software and then trying to solve that problem later. I changed quite nothing (a simple if after a button is pressed) and magically the error we were discussing about went away.... my hypothesis is that, upgrading to Snow Leopard and the new Xcode 3.2 and changing to llvm/clang something in linking libraries broke up. Then (even if i did several clean all) something turned in place while I re-built the project after modifying some bit of code so the compiler had to re-link the libraries.
w4nderlust
+2  A: 

While probably not the cause of your crash, you are leaking memory by not releasing the context2, unmasked, and mask Core Foundation objects using CFRelease(), CFImageRelease(), or the like.

Brad Larson
Added CGContextRelease() and CGImageRelease() , thank you for the suggestion ;)
w4nderlust
+1  A: 

Having similar issue with very simple code dealing with UIImage only on iPhone 3.0 simulator.

This only started happening after I upgraded to Snow Leopard and XCode 3.2 with iPhone SDK 3.1

Testing on device or Simulator 3.1 seems to work without any errors.

Maybe some bug in apple's frameworks?

This is the code in my UIImageExtension (category on UIImage)

- (UIImage*)imageByScalingAndCroppingForSize:(CGSize)targetSize
{
    UIGraphicsBeginImageContext( targetSize );
    [self drawInRect:CGRectMake(0,0,targetSize.width,targetSize.height)];
    UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return newImage;
}

This is the warning in console:

malloc: *** error for object 0x1a6b000: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug

This is the backtrace

#0  0x95b3a27e in malloc_error_break ()
#1  0x95a49203 in free ()
#2  0x0025ce49 in dataReleaseInfo ()
#3  0x002481d9 in data_provider_finalize ()
#4  0x30204421 in _CFRelease ()
#5  0x00247fa2 in image_finalize ()
#6  0x30204421 in _CFRelease ()
#7  0x30906f14 in -[UIImage dealloc] ()
#8  0x30506515 in NSPopAutoreleasePool ()
#9  0x30901697 in _UIApplicationHandleEvent ()
#10 0x32046375 in PurpleEventCallback ()
#11 0x30245560 in CFRunLoopRunSpecific ()
#12 0x30244628 in CFRunLoopRunInMode ()
#13 0x32044c31 in GSEventRunModal ()
#14 0x32044cf6 in GSEventRun ()
#15 0x309021ee in UIApplicationMain ()
#16 0x000027a2 in main (argc=1, argv=0xbfffefd8) at /Volumes/.../main.mm:14
CJ Hanson
I did a really similar function that scales the image to a specified size. It gave me also the same memory allocation error, but, as i said, now (i don't know why) it isn't giving the error. I think it's something messing with the libraries in the upgrade, is the only thing i can think of.
w4nderlust
A: 

I had the same issue with the following code.

-(void)adjustImageToImageView:(UIImage*)img{

float numPixels = 100;
float radius = 5;
UIGraphicsBeginImageContext(CGSizeMake(numPixels, numPixels));
CGContextRef c = UIGraphicsGetCurrentContext();

CGContextBeginPath(c);
CGContextMoveToPoint  (c, numPixels, numPixels/2);
CGContextAddArcToPoint(c, numPixels, numPixels, numPixels/2, numPixels,   radius);
CGContextAddArcToPoint(c, 0,         numPixels, 0,           numPixels/2, radius);
CGContextAddArcToPoint(c, 0,         0,         numPixels/2, 0,           radius);
CGContextAddArcToPoint(c, numPixels, 0,         numPixels,   numPixels/2, radius);
CGContextClosePath(c);

CGContextClip(c);

[img drawAtPoint:CGPointZero];
UIImage *converted = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
self.imageView.image = converted;   }

I took the function from the open source Twitterfon app.

When I was trying to fix the issue, I tried changing the last line to

self.imageView.image = [converted retain]

And that stopped the error messages in the console. I'm going to check this in Leaks soon to see whats happening.

cocoaholic
I just ran Leaks. The app is leaking the UIImage. So this is definitely not a solution! Interesting that the malloc errors were suppressed by this though.
cocoaholic
+18  A: 

I've had the same problem, with a lot of the same symptoms:

  • pointer being freed was not allocated error
  • upgraded to Xcode 3.2
  • error happening in code for images

If I change the build target to 3.1, the errors in the simulator go away. If I run the code on the device, the errors don't appear. Possibly a bug in 3.0

My advice is to test with 3.1 as your target, and if you want, you can build for 3.0 for release and not worry about the errors as they don't happen on the device.

nevan
It looks like a bug in 3.0, since I also had this issue and it went away when I set the target to 3.1.
lucius
Just to say that I had exactly the same problem, and setting 3.1 solved also in my case. Thanks
Andy
Another "me too". Looks like a bug in 3.0 simulator specifically. Testing in 3.1+ in simulator and 3.0 on device are both fine.
Chris Miles
Thanks for this great info.....You saved my time..
Sijo
A: 

I just wanted to confirm, again, that I had was getting:

pointer being freed was not allocated

error and it went away if i change my target os to 3.1 as opposed to 3.0

mracoker
Yep, same for me. `UIGraphicsGetImageFromCurrentImageContext()` is supposed to return an autoreleased UIImage, but it seems to be double autoreleasing it, ONLY in the 3.0 simulator and ONLY with Xcode 3.2
Matt Rix
A: 

I've struggled with the same error in my code. What I was puzzled by is that my app worked in OS 3.0 without any problem until I made a minor modification to a code that has nothing to do with the CGImage* stuff. But once it started to fail, then it never worked without crashing. When I switched to 3.1, everything worked again. I narrowed down the error to a CGImageRelease() call. Either removing that line or adding a retain on the resulting UIImage resolved the problem--although this is a no solution since the app will be leaking memory.

I tried using NSZombie with instruments. This didn't help--the app crashed without any zombies being detected.

Furthermore, Apple's own example apps (like TheElements) does NOT crash but uses the same EXACT code as my app. So, I'm struggling to accept the problem lies in the Frameworks. For now, I am switching to 3.1 and moving on.

Genzeb
A: 

It might be just me but you can't do the following ?

UIImage *whiteMasked = UIGraphicsGetImageFromCurrentImageContext();

UIGraphicsEndImageContext();

return whiteMasked;

whiteMasked is allocated on the stack of the function and after it returns the pointer is no longer valid? Or am I missing something? If you use the returned UIImage* it is not guaranteed to still be there. (it would be a hit and miss). Don't you need to alloc a UIImage* and then autorelease it before returning?

dkardell
Objects in Cocoa/Objective-C are always allocated on the heap, never on the stack. The pointer stored in `whiteMasked` is valid at least until the current autorelease pool is drained, which won't be until the end of the event loop. It's fine to be used in this function and it's fine to return it, too. We would only need to make a copy if we planned on saving it and using the same image later (say, in an instance variable).
benzado