Re: Memory Management
Re: Memory Management
- Subject: Re: Memory Management
- From: Nat! <email@hidden>
- Date: Fri, 10 Aug 2001 23:07:52 +0200
Am Mittwoch, 8. August 2001 um 20:05 schrieb Robert Thompson:
>
----- Original Message -----
>
From: "Nat!" <email@hidden>
>
> //
>
> // (gdb) Starting program: /Network/Users/nat/src/test/test
>
> // [Switching to process 759 thread 0x2600]
>
> // Aug 08 02:05:00 test[759] 0 : <SonOfJekyll: 0x4ebf8> = 660
>
> // Aug 08 02:05:00 test[759] 1 : <SonOfJekyll: 0x4ebf8> = 665
>
> // Aug 08 02:05:00 test[759] 2 : <SonOfJekyll: 0x51050> = 664
>
> // Aug 08 02:05:00 test[759] 3 : <SonOfJekyll: 0x51050> = 661
>
> // Aug 08 02:05:00 test[759] 4 : <SonOfJekyll: 0x51050> = 664
>
> // Aug 08 02:05:00 test[759] 5 : <SonOfJekyll: 0x51050> = 669
>
> // Aug 08 02:05:00 test[759] 6 : <SonOfJekyll: 0x51050> = 662
>
> // Aug 08 02:05:00 test[759] 7 : <SonOfJekyll: 0x51050> = 665
>
> //
>
> // Program received signal SIGSEGV, Segmentation fault.
>
> //
>
>
>
Ummm... when I run the program (on Mac OS X 10.0.4), I get this:
>
Aug 08 13:58:47 jekyll[11625] 0 : <SonOfJekyll: 0x914a0> = 660
>
Aug 08 13:58:47 jekyll[11625] 1 : <SonOfJekyll: 0x914a0> = 665
>
Aug 08 13:58:47 jekyll[11625] 2 : <SonOfJekyll: 0x914a0> = 664
>
Aug 08 13:58:47 jekyll[11625] 3 : <SonOfJekyll: 0x914a0> = 661
>
Aug 08 13:58:47 jekyll[11625] 4 : <SonOfJekyll: 0x914a0> = 664
>
Aug 08 13:58:47 jekyll[11625] 5 : <SonOfJekyll: 0x914a0> = 669
>
Aug 08 13:58:47 jekyll[11625] 6 : <SonOfJekyll: 0x914a0> = 662
>
Aug 08 13:58:47 jekyll[11625] 7 : <SonOfJekyll: 0x914a0> = 665
>
Aug 08 13:58:47 jekyll[11625] 8 : <Hyde: 0x975f0> = 666
>
Aug 08 13:58:47 jekyll[11625] 9 : <SonOfJekyll: 0x914a0> = 667
>
Aug 08 13:58:47 jekyll[11625] 10 : <SonOfJekyll: 0x914a0> = 668
>
Aug 08 13:58:47 jekyll[11625] 11 : <SonOfJekyll: 0x914a0> = 661
>
Aug 08 13:58:47 jekyll[11625] 12 : <Hyde: 0x975f0> = 666
>
Aug 08 13:58:47 jekyll[11625] 13 : <SonOfJekyll: 0x914a0> = 661
>
.... and so on up to 100 lines
>
>
Interestingly, though, if I add a method to print comment when
>
amIEvil ==
>
666, I get
>
Aug 08 14:04:23 jekyll[11765] 0 : <SonOfJekyll: 0x91490> = 660
>
Aug 08 14:04:23 jekyll[11765] 1 : <SonOfJekyll: 0x91490> = 665
>
Aug 08 14:04:23 jekyll[11765] 2 : <SonOfJekyll: 0x91490> = 664
>
Aug 08 14:04:23 jekyll[11765] 3 : <SonOfJekyll: 0x91490> = 661
>
Aug 08 14:04:23 jekyll[11765] 4 : <SonOfJekyll: 0x91490> = 664
>
Aug 08 14:04:23 jekyll[11765] 5 : <SonOfJekyll: 0x91490> = 669
>
Aug 08 14:04:23 jekyll[11765] 6 : <SonOfJekyll: 0x91490> = 662
>
Aug 08 14:04:23 jekyll[11765] 7 : <SonOfJekyll: 0x91490> = 665
>
Aug 8 14:04:23 jekyll[11765] Got nil as the string argument in
>
NSMutableString. Pass empty string instead. Will probably crash.
>
Bus error
>
Hey I guess then there's no problem there at all :)
But seriously, though... You can probably reproduce the crash on your
machine if you increase the number of XXXs in the initWithComment call.
Here is a little background info as to why it crashes, in case that
isn't obvious.
The problem is that the original initWithValue: of Jekyll may return an
object of type Hyde instead of the object called on. Now Hyde is about 8
bytes large. 4 bytes for the isa pointer and 4 bytes for the integer
(and then maybe some padding). (check
http://www.mulle-
kybernetik.com/opti-2.html for a short intro into object memory layout)
@interface Jekyll : NSObject
{
int amIEvil;
}
@interface Hyde : Jekyll
{
}
@end
The subclass SonOfJekyll is 1024 bytes longer.
@interface SonOfJekyll : Jekyll
{
char comment[ 1024]; // so our subclass does need some more
ivar space...
}
The problem arises when in the SonOfJekyll we write the method like this
- (id) initWithComment:(char *) s
{
// blessed are the meek for they shall inherit ...
if( (self = [super initWithValue:rand() % 10 + 660]) == nil)
return( self);
strncpy( comment, s, sizeof( comment));
return( self);
}
because if we get a Hyde object back we only have room for 8 bytes and
the strncpy will clobber memory which is not ours. If we get a regular
SonOfJekyll object back (the one we called super initWithValue: on),
everything's fine.
This learns us that
if( (self = [super init...]) != nil)
{
}
only handles the nil case properly, and maybe a few cases where the
returned object is not the same as previous self and the size of the
objects are the same (HIGHLY unlikely), in this sense I find the
"self = " is misleading, for those (Mike) who didn't get it.
It is still my opinion that you should not blindly code init methods
but... enough of this.
Nat!