On Tue, Apr 26, 2011 at 9:17 PM, Eric Wasylishen <[email protected]>wrote:

> Hey.
> -[NSNumberFormatter init] has this block of code:
>
>  internal->_behavior = _defaultBehavior;
>  internal->_locale = RETAIN([NSLocale currentLocale]);
>  internal->_style = NSNumberFormatterNoStyle;
>  internal->_symbols = NSZoneCalloc (z, MAX_SYMBOLS, sizeof(id));
>  internal->_textAttributes = NSZoneCalloc (z, MAX_TEXTATTRIBUTES,
> sizeof(id));
>  internal->_attributes = NSZoneCalloc (z, MAX_ATTRIBUTES, sizeof(int));
>
> which allocates some C arrays.  However, these ivars are never initialized
> if you use -initWithCoder:, and so if you call -setDecimalSeparator: on a
> instance loaded from a nib, you'll get a segfault in this line of code in
> the SET_SYMBOL macro:
>
>  if (internal->_symbols[key])
>
> since the internal->_symbols will be NULL at that point.
>

Thanks for spotting that.  I seem to have forgotten about the NSCoding
protocol when I added these new ivars.  I see where someone (can't remember
if it was me or not) added a FIXME tag in -initWithCoder:.

I have a couple of comments about this:
>
> 1. The SET_SYMBOL macro wasted me a significant amount of time because I
> had to expand it by hand to locate the segfault. Is there a reason this
> isn't a private instance method instead of a macro? (same with
> SET_TEXTATTRIBUTE, SET_ATTRIBUTE, SET_BOOL, GET_SYMBOL, GET_ATTRIBUTE,
> GET_BOOL).
> Sorry to sound negative; the new NSNumberFormatter implementation looks
> really nice otherwise :-)
>

I don't have a good reason as to why I did it.  I originally used methods
but later changed it to macros.


> 2. I've seen this mistake (-initWithCoder not doing everything -init does)
> before, and I expect it occurs elsewhere in GNUstep. Do we have a policy on
> how to prevent this from happening in the future? i.e. what's the right way
> to implement -initWithCoder and -init? I think we should have a standard
> pattern we use everywhere.
>

I'm OK with this or the private method you mentioned in your other e-mail.
I can't promise I'll get to it right away, though... I haven't had a lot of
personal time lately.


>  - We don't want them to share large chunks of copy-and-pasted code since
> this is error prone.
>  - Calling -init (or the designated initializer) directly from
> -initWithCoder could cause problems since it could conflict with the
> required call to [super initWithCoder: ];
>  - The only idea I can think of right now is factoring out the common code
> in to a static function like this:
>
> - (id) init
> {
>        self = [super init];
>        privateInit(self);
>        return self;
> }
>
> - (id)initWithCoder: (NSCoder*)coder
> {
>        self = [super initWithCoder: coder];
>        privateInit(self);
>
>        if ([coder containsValueForKey: @"foo"]) [self setFoo: [coder
> decodeObjectForKey: @"foo"]];
>        if ([coder containsValueForKey: @"bar"]) [self setBar: [coder
> decodeObjectForKey: @"bar"]];
>        ...
>        return self;
> }
>
> static void privateInit(MyClass *self)
> {
>        self->someCArray = malloc(100);
>        self->someValue = 123;
>        ...
> }
>
> Note that the privateInit function only sets up ivars belonging to the
> current class, so each superclass would have its own privateInit function to
> set up the ivars belonging to that superclass.
>
> How does that pattern look?
>
> --Eric
> _______________________________________________
> Gnustep-dev mailing list
> [email protected]
> https://lists.gnu.org/mailman/listinfo/gnustep-dev
>
_______________________________________________
Gnustep-dev mailing list
[email protected]
https://lists.gnu.org/mailman/listinfo/gnustep-dev

Reply via email to