[Pyobjc-dev] Bug Fixed!!! Dealing with alloc / init oddities
Brought to you by:
ronaldoussoren
From: Bill B. <bb...@co...> - 2002-10-24 14:32:15
|
(Another "debugging out loud" session -- but this one ended happily. I'll put the 'solution' first and those interested can read down for the details that led to it...) #if 1 self_obj = nil; if (*[methinfo methodReturnType] == _C_ID) { [inv setReturnValue:&self_obj]; } [inv setTarget:self_obj]; [inv setArgument:&self_obj atIndex:0]; #endif [inv release]; [methinfo release]; inv = nil; The above is found in objc_support.m around line 1423. By changing the "#if 1" to an "#if 0", the bug goes away and all unit tests pass (except invocation of class methods when an instance method of the same name also exists). The code #if'd in/out looks to be there to force the NSInvocation to clean up after itself. In theory, that should be handled by the [inv -release] on the line immediately after that block of code. In practice, this still shouldn't cause a crash assuming that the NSInvocation only retains things that it releases. Why the crash was happening isn't clear to me. The [lack of the above] code may also potentially be causing a memory leak? Change committed. --- I believe I have tracked the crasher w/the collection classes down to being related to the following behavior of NSArray: int main (int argc, const char * argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; NSArray *a; a = [NSMutableArray alloc]; NSLog(@"0x%x", a); a = [a init]; NSLog(@"0x%x", a); a = [NSMutableArray alloc]; NSLog(@"0x%x", a); a = [a init]; NSLog(@"0x%x", a); [pool release]; return 0; } The above outputs -- of note, If I change the second [NSMutableArray alloc] to [NSArray alloc], the output remains *unchanged*. 2002-10-24 09:35:37.398 barfoo[19606] 0x4b580 2002-10-24 09:35:37.424 barfoo[19606] 0x57c90 2002-10-24 09:35:37.439 barfoo[19606] 0x4b580 2002-10-24 09:35:37.452 barfoo[19606] 0x57cb0 Clearly, the Foundation/Core are playing games with the NSArray/NSMutableArray class clusters. The +alloc methods return placeholders that are turned into the appropriate instance upon initialization. This makes sense given that the -init* method used determines the role and, hence, the appropriate private subclass, of the instance of the class cluster. Now, consider the following: [bumbox:~/bbum-developer/sourceforge/pyobjc] bbum% python >>> from Foundation import * >>> NSArray.alloc().init() () >>> NSMutableArray.alloc().init() () >>> NSArray.alloc().init() 2002-10-24 09:37:46.189 python[19612] Did you forget to nest alloc and init? 2002-10-24 09:37:46.191 python[19612] *** Uncaught exception: <NSInvalidArgumentException> *** -length only defined for abstract class. Define -[NSPlaceholderMutableString length]! It appears that the bridge somehow caches the placeholder instance and ends up releasing or corrupting it upon the second call to the alloc() method *for that particular class*? Given that last bug, it seems like the shared placeholder array instance may be being released one time to many?? It is! (see above) |