views:

235

answers:

3

I've searched far and wide for its meaning. My guess is that I somehow have a corrupt stack. I get

tiny _ free_ list_ add_ ptr

on the 16th call of the line that says:

NSDateFormatter *theFormatter = [[NSDateFormatter alloc] init];

What is the cause of the problem? Am I correct in thinking that I have a corrupt stack?

    - (NSString *)formatDate:(NSString *)uglyDate withFormat:(NSString *)theFormat {

    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    NSDateFormatter *theFormatter = [[NSDateFormatter alloc] init];
    [theFormatter setDateFormat:theFormat];

    NSDate *realDateUgly = [NSDate dateWithNaturalLanguageString:uglyDate];
    if (realDateUgly == nil)
        realDateUgly = [NSDate dateWithString:uglyDate];

    NSString *prettyDate = [[NSString alloc] initWithString:[theFormatter stringFromDate:realDateUgly]];

    [pool drain];
    [pool release];    
    [theFormatter release];
    return prettyDate;

}
+1  A: 
  1. I doubt you need a pool here.
  2. You're over-releasing the pool. drain is the same as release in non-GC code. (release is just as redundant in GC code, because then it's a no-op.)
  3. You're leaking prettyDate. You're supposed to autorelease it. (Of course, that won't work with the pool around it, which is a good reason to kill off that pool.)

Once you review the Memory Management Programming Guide for Cocoa and fix your memory-management problems, you should either find the problem fixed or at least be better able to track it down.

If you do still have the problem after you fix your memory management, please edit your question to include the complete stack trace.

Peter Hosey
Thanks for your quick response. I shouldn't have glossed over the Autorelease section so quick. I took your advice and removed the pool. As for pretty date, I changed it to this:NSString *prettyDate = [theFormatter stringFromDate:realDateUgly];The problem is no longer in this function, but elsewhere. I'll be studying the Memory Management Programming Guide for Cocoa. Thanks again.
JCS007
Actually, one more thing: I would still like to know what tiny_free_list_add_ptr is. Just curious. :)
JCS007
An internal function, presumably within the malloc machinery (having to do with the free list).
Peter Hosey
A: 

I assume you're crashing in tiny_free_list_add_ptr. If so, tiny_free_list_add_ptr sounds like a function that a malloc implementation would use to keep track of memory blocks on the heap. If the heap is corrupted, I would expect a function like this to crash.

You're probably over releasing something (like the auto release pool that peter pointed out) here or in another method.

You should try running with the NSZombiesEnabled environment variable set. See http://developer.apple.com/technotes/tn2004/tn2124.html#SECFOUNDATION

Jon Hess
A: 

I'd be willing to bet the problem is this:

[pool drain];
[pool release];

In a non-GC app, drain 'behaves' like release. 'Behaves' is the word used in the documentation, but the documentation is a bit ambiguous when you need to be pedantically precise as to exactly what happens when -drain is called. To me, at least, 'behaves' allows for a little bit of wiggle room, especially when compared to 'drain is exactly the same as release', which leaves a lot less room for interpretation.

The reason I bring this up is 'what happens to the autorelease pool after -drain is called?' I could not find a satisfactory answer in the documentation to this question. In different places, the documentation implies that when running in GC mode, -drain behaves as a 'hint to the GC system' and calls objc_collect_if_needed(). I could find nothing that explicitly says that when running in GC mode, an autorelease pool that has been sent a -drain message is 'no longer valid' (ie, something along the lines of behaving as if it was sent a release message). Nothing I could find in the documentation seems to expressly forbid sending an instantiated NSAutoreleasePool object a -drain message multiple times when running under GC.

The closest thing I could find was near the top of the NSAutoreleasePool class documentation: 'draining a pool ultimately has the effect of deallocating it'. This does little to help us here, though. The context from which this was taken is not terribly clear as to whether or not this applies to GC or non-GC mode. In any case, it is qualified with 'ultimately', which by pedantic dictionary definition means 'not now, but eventually'. Without the 'ultimately' qualification it's unambiguous as to whether or not the the instantiated autorelease pool object has been deallocated, and by induction, that sending additional messages to that pointer will result in undefined behavior.

So, since I can't point to anything authoritative to back this up, it's my opinion that -drain, in non-GC mode, behaves 'exactly' like -release (most likely implemented internally as [self release]). If this is true, you have 'over released' the NSAutoreleasePool object, in which case the problem will go away if you comment out one of the two statements.

johne
Very thorough. I like that.
JCS007