Using static NSString as observation context

  • I have recently changed some KVO observation code to us a static
    NSString as the context when registering as KVO observation. However
    now that seems to have introduced a crasher when removing the
    observer, at least on a Core Duo Intel machine. PPC does not seem to
    have any problem. So is there some problem using NSStrings as
    observation context for Intel? The Sketch sample code also uses those.

    Christiaan
  • On 17/05/2008, at 11:59 PM, Christiaan Hofman wrote:

    > I have recently changed some KVO observation code to us a static
    > NSString as the context when registering as KVO observation. However
    > now that seems to have introduced a crasher when removing the
    > observer, at least on a Core Duo Intel machine. PPC does not seem to
    > have any problem. So is there some problem using NSStrings as
    > observation context for Intel? The Sketch sample code also uses those.

    I've not had a problem, but I cast the string to a void*. I use a
    definition like this:

    static void* MyObservationContext=(void*) @"MyObservationContext";

    --
    Rob Keniger
  • On 18 May 2008, at 4:44 AM, Rob Keniger wrote:

    >
    > On 17/05/2008, at 11:59 PM, Christiaan Hofman wrote:
    >
    >> I have recently changed some KVO observation code to us a static
    >> NSString as the context when registering as KVO observation.
    >> However now that seems to have introduced a crasher when removing
    >> the observer, at least on a Core Duo Intel machine. PPC does not
    >> seem to have any problem. So is there some problem using NSStrings
    >> as observation context for Intel? The Sketch sample code also uses
    >> those.
    >
    >
    > I've not had a problem, but I cast the string to a void*. I use a
    > definition like this:
    >
    > static void* MyObservationContext=(void*) @"MyObservationContext";
    >
    > --
    > Rob Keniger

    Thanks, I'll try it. Though I can't test it myself, as I don't see the
    crash myself. It's a user reporting the problem (and the only change
    in the relevant object's code has been the use of a context, that's
    why I know it must be the cause).

    Christiaan
  • On Sun, May 18, 2008 at 12:23 PM, Christiaan Hofman <cmhofman...>
    wrote:

    >
    > On 18 May 2008, at 4:44 AM, Rob Keniger wrote:
    >
    >
    >> On 17/05/2008, at 11:59 PM, Christiaan Hofman wrote:
    >>
    >> I have recently changed some KVO observation code to us a static NSString
    >>> as the context when registering as KVO observation. However now that seems
    >>> to have introduced a crasher when removing the observer, at least on a Core
    >>> Duo Intel machine. PPC does not seem to have any problem. So is there some
    >>> problem using NSStrings as observation context for Intel? The Sketch sample
    >>> code also uses those.
    >>>
    >>
    >>
    >> I've not had a problem, but I cast the string to a void*. I use a
    >> definition like this:
    >>
    >> static void* MyObservationContext=(void*) @"MyObservationContext";
    >>
    >> --
    >> Rob Keniger
    >>
    >
    > Thanks, I'll try it. Though I can't test it myself, as I don't see the
    > crash myself. It's a user reporting the problem (and the only change in the
    > relevant object's code has been the use of a context, that's why I know it
    > must be the cause).
    >
    > Christiaan
    >
    >
    But can this really make a difference? Aren't they both just the same size
    (that is, pointer size), for any architecture? And the pointer should never
    be resolved anywhere (I definitely don't, I only compare using ==).

    Christiaan
  • On Sat, May 17, 2008 at 7:44 PM, Rob Keniger <rob...> wrote:
    >
    > On 17/05/2008, at 11:59 PM, Christiaan Hofman wrote:
    >
    >> I have recently changed some KVO observation code to us a static NSString
    >> as the context when registering as KVO observation. However now that seems
    >> to have introduced a crasher when removing the observer, at least on a Core
    >> Duo Intel machine. PPC does not seem to have any problem. So is there some
    >> problem using NSStrings as observation context for Intel? The Sketch sample
    >> code also uses those.
    >
    >
    > I've not had a problem, but I cast the string to a void*. I use a definition
    > like this:
    >
    > static void* MyObservationContext=(void*) @"MyObservationContext";

    What is the point of doing this? Why are you trying to throw away type
    information?

    -Shawn
  • On 18 May 2008, at 8:31 PM, Shawn Erickson wrote:

    > On Sat, May 17, 2008 at 6:59 AM, Christiaan Hofman
    > <cmhofman...> wrote:
    >> I have recently changed some KVO observation code to us a static
    >> NSString as
    >> the context when registering as KVO observation. However now that
    >> seems to
    >> have introduced a crasher when removing the observer, at least on a
    >> Core Duo
    >> Intel machine. PPC does not seem to have any problem. So is there
    >> some
    >> problem using NSStrings as observation context for Intel? The
    >> Sketch sample
    >> code also uses those.
    >
    > Can you be more specific about the crash you are seeing? (backtrace,
    > etc.)
    >

    This is the top part of the crash

    Thread 0 Crashed:
    0 libobjc.A.dylib 0x90a59380 objc_msgSend + 16
    1 com.apple.Foundation 0x928a26a7
    -[NSObject(NSKeyValueObserverRegistration) removeObserver:forKeyPath:] +
    233
    2 com.apple.AppKit 0x93534a02 -[NSController
    removeObserver:forKeyPath:] + 208

    After that comes some app specific trace that clearly points to a
    particular -removeObserver:forKeyPath: on NSUserDefaultsController in -
    windowWillClose: for the main document window.

    > Are you removing the observation of the same key more then once? I
    > have seen a over release bug in the Cocoa framework in situations like
    > this (trying to locate my information on that issue...).
    >
    > -Shawn

    No, -windowWillClose: can never be called twice, because the document
    is closed after that. And the corresponding -addObserver:... is called
    in -windowControllerDidLoadNib:, which is called for sure.

    Christiaan
  • On May 18, 2008, at 11:29 AM, Shawn Erickson wrote:

    >> static void* MyObservationContext=(void*) @"MyObservationContext";
    >
    > What is the point of doing this? Why are you trying to throw away type
    > information?

    Probably to supress compiler warnings?

          - Scott
  • On 19/05/2008, at 8:45 AM, Scott Stevenson wrote:

    >>> static void* MyObservationContext=(void*) @"MyObservationContext";
    >>
    >> What is the point of doing this? Why are you trying to throw away
    >> type
    >> information?
    >
    > Probably to supress compiler warnings?

    Exactly. The method you use the context in has this signature so if
    you don't cast to a void* you get a compiler warning:

    - (void)addObserver:(NSObject *)anObserver forKeyPath:(NSString
    *)keyPathoptions:(NSKeyValueObservingOptions)options context:(void
    *)context

    --
    Rob Keniger
  • On Sun, May 18, 2008 at 6:15 PM, Rob Keniger <rob...> wrote:
    >
    > On 19/05/2008, at 8:45 AM, Scott Stevenson wrote:
    >
    >>>> static void* MyObservationContext=(void*) @"MyObservationContext";
    >>>
    >>> What is the point of doing this? Why are you trying to throw away type
    >>> information?
    >>
    >> Probably to supress compiler warnings?
    >
    > Exactly. The method you use the context in has this signature so if you
    > don't cast to a void* you get a compiler warning:

    You can assign any typed pointer to a void* without any warnings.
    (unless you have some unusual warning enabled)

    Anyway my question was more of what does this have to do with the
    crash that the OP posted?

    -Shawn
  • On 19 May 2008, at 5:07 PM, Shawn Erickson wrote:

    > On Sun, May 18, 2008 at 6:15 PM, Rob Keniger <rob...>
    > wrote:
    >>
    >> On 19/05/2008, at 8:45 AM, Scott Stevenson wrote:
    >>
    >>>>> static void* MyObservationContext=(void*) @"MyObservationContext";
    >>>>
    >>>> What is the point of doing this? Why are you trying to throw away
    >>>> type
    >>>> information?
    >>>
    >>> Probably to supress compiler warnings?
    >>
    >> Exactly. The method you use the context in has this signature so if
    >> you
    >> don't cast to a void* you get a compiler warning:
    >
    > You can assign any typed pointer to a void* without any warnings.
    > (unless you have some unusual warning enabled)
    >
    > Anyway my question was more of what does this have to do with the
    > crash that the OP posted?
    >
    > -Shawn

    Indeed. The only way I think typing could have an effect of avoiding
    such a crash is when there is a difference in size (or perhaps
    endianess), so typing actually would do some real conversion. Hence my
    question earlier. However I'm pretty sure that can never be relevant
    for this case, as any pointer should have the same size (and nothing
    it points to gets allocated or deallocated).

    Christiaan
  • On Sun, May 18, 2008 at 1:27 PM, Christiaan Hofman <cmhofman...> wrote:
    >
    > On 18 May 2008, at 8:31 PM, Shawn Erickson wrote:
    >
    >> On Sat, May 17, 2008 at 6:59 AM, Christiaan Hofman <cmhofman...>
    >> wrote:
    >>>
    >>> I have recently changed some KVO observation code to us a static NSString
    >>> as
    >>> the context when registering as KVO observation. However now that seems
    >>> to
    >>> have introduced a crasher when removing the observer, at least on a Core
    >>> Duo
    >>> Intel machine. PPC does not seem to have any problem. So is there some
    >>> problem using NSStrings as observation context for Intel? The Sketch
    >>> sample
    >>> code also uses those.
    >>
    >> Can you be more specific about the crash you are seeing? (backtrace, etc.)
    >>
    >
    > This is the top part of the crash
    >
    > Thread 0 Crashed:
    > 0 libobjc.A.dylib 0x90a59380 objc_msgSend + 16
    > 1 com.apple.Foundation 0x928a26a7
    > -[NSObject(NSKeyValueObserverRegistration) removeObserver:forKeyPath:] +
    > 233
    > 2 com.apple.AppKit 0x93534a02 -[NSController
    > removeObserver:forKeyPath:] + 208
    >
    > After that comes some app specific trace that clearly points to a particular
    > -removeObserver:forKeyPath: on NSUserDefaultsController in -windowWillClose:
    > for the main document window.

    That type of crash implies to me that the object you (indirectly) are
    sending removeObserver:forKeyPath: to is no longer a valid object. Try
    debugging with NSZombie enabled.

    -Shawn
  • On 19 May 2008, at 5:39 PM, Shawn Erickson wrote:

    > On Sun, May 18, 2008 at 1:27 PM, Christiaan Hofman
    > <cmhofman...> wrote:
    >>
    >> On 18 May 2008, at 8:31 PM, Shawn Erickson wrote:
    >>
    >>> On Sat, May 17, 2008 at 6:59 AM, Christiaan Hofman <cmhofman...>
    >>>>
    >>> wrote:
    >>>>
    >>>> I have recently changed some KVO observation code to us a static
    >>>> NSString
    >>>> as
    >>>> the context when registering as KVO observation. However now that
    >>>> seems
    >>>> to
    >>>> have introduced a crasher when removing the observer, at least on
    >>>> a Core
    >>>> Duo
    >>>> Intel machine. PPC does not seem to have any problem. So is there
    >>>> some
    >>>> problem using NSStrings as observation context for Intel? The
    >>>> Sketch
    >>>> sample
    >>>> code also uses those.
    >>>
    >>> Can you be more specific about the crash you are seeing?
    >>> (backtrace, etc.)
    >>>
    >>
    >> This is the top part of the crash
    >>
    >> Thread 0 Crashed:
    >> 0 libobjc.A.dylib 0x90a59380 objc_msgSend + 16
    >> 1 com.apple.Foundation 0x928a26a7
    >> -[NSObject(NSKeyValueObserverRegistration)
    >> removeObserver:forKeyPath:] +
    >> 233
    >> 2 com.apple.AppKit 0x93534a02 -[NSController
    >> removeObserver:forKeyPath:] + 208
    >>
    >> After that comes some app specific trace that clearly points to a
    >> particular
    >> -removeObserver:forKeyPath: on NSUserDefaultsController in -
    >> windowWillClose:
    >> for the main document window.
    >
    > That type of crash implies to me that the object you (indirectly) are
    > sending removeObserver:forKeyPath: to is no longer a valid object. Try
    > debugging with NSZombie enabled.
    >
    > -Shawn

    That object is NSUserDefaultsController. That cannot be invalid
    (unless there is a bug in AppKit).

    Christiaan
  • On 19 May 2008, at 17:48, Christiaan Hofman wrote:
    >
    > On 19 May 2008, at 5:39 PM, Shawn Erickson wrote:
    >>
    >> That type of crash implies to me that the object you (indirectly) are
    >> sending removeObserver:forKeyPath: to is no longer a valid object.
    >> Try
    >> debugging with NSZombie enabled.
    >>
    >> -Shawn
    >
    > That object is NSUserDefaultsController. That cannot be invalid
    > (unless there is a bug in AppKit).

    Not quite. Observers are implemented with some other hidden objects
    and method redirection in the mix, so the remove message may not be
    going direct to the NSUserDefaultsController.
  • On 19 May 2008, at 7:56 PM, Paul Sargent wrote:

    >
    > On 19 May 2008, at 17:48, Christiaan Hofman wrote:
    >>
    >> On 19 May 2008, at 5:39 PM, Shawn Erickson wrote:
    >>>
    >>> That type of crash implies to me that the object you (indirectly)
    >>> are
    >>> sending removeObserver:forKeyPath: to is no longer a valid object.
    >>> Try
    >>> debugging with NSZombie enabled.
    >>>
    >>> -Shawn
    >>
    >> That object is NSUserDefaultsController. That cannot be invalid
    >> (unless there is a bug in AppKit).
    >
    > Not quite. Observers are implemented with some other hidden objects
    > and method redirection in the mix, so the remove message may not be
    > going direct to the NSUserDefaultsController.

    Should not be relevant. I only send it
    addObserver:forKeyPath:options:context: and removeObserver:forKeyPath:
    messages. So even if they are forwarded to some other hidden objects,
    they should never lead to over releasing. And the add/remove messages
    are balanced, I can assure that.

    Christiaan
  • On 19 May 2008, at 7:56 PM, Paul Sargent wrote:

    >
    > On 19 May 2008, at 17:48, Christiaan Hofman wrote:
    >>
    >> On 19 May 2008, at 5:39 PM, Shawn Erickson wrote:
    >>>
    >>> That type of crash implies to me that the object you (indirectly)
    >>> are
    >>> sending removeObserver:forKeyPath: to is no longer a valid object.
    >>> Try
    >>> debugging with NSZombie enabled.
    >>>
    >>> -Shawn
    >>
    >> That object is NSUserDefaultsController. That cannot be invalid
    >> (unless there is a bug in AppKit).
    >
    > Not quite. Observers are implemented with some other hidden objects
    > and method redirection in the mix, so the remove message may not be
    > going direct to the NSUserDefaultsController.

    The only other objects I can think of to be in play are the observer,
    which should definitely be valid at this point, and the shared
    NSUserDefaults object, which is the one ultimately being observed.

    I am now pretty sure the static NSString must be a red haring. There
    should be some other invalid object. As I'm pretty sure it's neither
    the observer nor the controller, the only object I can think of is
    NSUserDefaults.

    One thing I've noticed: all crash reports are with 10.4 on a MacBook.
    So I start to believe there is a Tiger AppKit bug involved. Has anyone
    else seen problems with KVO on NSUserDefaultsController on Tiger?

    Christiaan
  • If you overrelease an object, including the user defaults controller,
    it could be deallocated.  Also, if an object is overreleased and gets
    deallocated, that memory location can end up reused for some other
    object.

    Did you try running with zombies, as Shawn suggested?  I would not
    suspect a cocoa bug here.

    -Ken

    On Tue, May 27, 2008 at 5:56 AM, Christiaan Hofman <cmhofman...> wrote:
    >
    > On 19 May 2008, at 7:56 PM, Paul Sargent wrote:
    >
    >>
    >> On 19 May 2008, at 17:48, Christiaan Hofman wrote:
    >>>
    >>> On 19 May 2008, at 5:39 PM, Shawn Erickson wrote:
    >>>>
    >>>> That type of crash implies to me that the object you (indirectly) are
    >>>> sending removeObserver:forKeyPath: to is no longer a valid object. Try
    >>>> debugging with NSZombie enabled.
    >>>>
    >>>> -Shawn
    >>>
    >>> That object is NSUserDefaultsController. That cannot be invalid (unless
    >>> there is a bug in AppKit).
    >>
    >> Not quite. Observers are implemented with some other hidden objects and
    >> method redirection in the mix, so the remove message may not be going direct
    >> to the NSUserDefaultsController.
    >
    > The only other objects I can think of to be in play are the observer, which
    > should definitely be valid at this point, and the shared NSUserDefaults
    > object, which is the one ultimately being observed.
    >
    > I am now pretty sure the static NSString must be a red haring. There should
    > be some other invalid object. As I'm pretty sure it's neither the observer
    > nor the controller, the only object I can think of is NSUserDefaults.
    >
    > One thing I've noticed: all crash reports are with 10.4 on a MacBook. So I
    > start to believe there is a Tiger AppKit bug involved. Has anyone else seen
    > problems with KVO on NSUserDefaultsController on Tiger?
    >
    > Christiaan
    >
    > _______________________________________________
    > MacOSX-dev mailing list
    > <MacOSX-dev...>
    > http://www.omnigroup.com/mailman/listinfo/macosx-dev
    >
  • I know, but I never send an (auto)release message to NSUserDefaults or
    NSUserDefaultsController, ever. Why would I, those are shared objects?
    That's my point of saying that the object is the shared
    NSUserDefaultsController, I thought that should be obvious. And it's
    pretty easy to check that I don't, because I can easily find every
    single occurrence where I send messages to those object in my code.

    Unfortunately I cannot debug this problem, as I don't see the bug. I
    only see the bug reports from my users. So running with zombies is
    pointless.

    Christiaan

    On 27 May 2008, at 7:49 PM, Ken Ferry wrote:

    > If you overrelease an object, including the user defaults controller,
    > it could be deallocated.  Also, if an object is overreleased and gets
    > deallocated, that memory location can end up reused for some other
    > object.
    >
    > Did you try running with zombies, as Shawn suggested?  I would not
    > suspect a cocoa bug here.
    >
    > -Ken
    >
    > On Tue, May 27, 2008 at 5:56 AM, Christiaan Hofman
    > <cmhofman...> wrote:
    >>
    >> On 19 May 2008, at 7:56 PM, Paul Sargent wrote:
    >>
    >>>
    >>> On 19 May 2008, at 17:48, Christiaan Hofman wrote:
    >>>>
    >>>> On 19 May 2008, at 5:39 PM, Shawn Erickson wrote:
    >>>>>
    >>>>> That type of crash implies to me that the object you
    >>>>> (indirectly) are
    >>>>> sending removeObserver:forKeyPath: to is no longer a valid
    >>>>> object. Try
    >>>>> debugging with NSZombie enabled.
    >>>>>
    >>>>> -Shawn
    >>>>
    >>>> That object is NSUserDefaultsController. That cannot be invalid
    >>>> (unless
    >>>> there is a bug in AppKit).
    >>>
    >>> Not quite. Observers are implemented with some other hidden
    >>> objects and
    >>> method redirection in the mix, so the remove message may not be
    >>> going direct
    >>> to the NSUserDefaultsController.
    >>
    >> The only other objects I can think of to be in play are the
    >> observer, which
    >> should definitely be valid at this point, and the shared
    >> NSUserDefaults
    >> object, which is the one ultimately being observed.
    >>
    >> I am now pretty sure the static NSString must be a red haring.
    >> There should
    >> be some other invalid object. As I'm pretty sure it's neither the
    >> observer
    >> nor the controller, the only object I can think of is NSUserDefaults.
    >>
    >> One thing I've noticed: all crash reports are with 10.4 on a
    >> MacBook. So I
    >> start to believe there is a Tiger AppKit bug involved. Has anyone
    >> else seen
    >> problems with KVO on NSUserDefaultsController on Tiger?
    >>
    >> Christiaan
    >>
    >> _______________________________________________
    >> MacOSX-dev mailing list
    >> <MacOSX-dev...>
    >> http://www.omnigroup.com/mailman/listinfo/macosx-dev
    >>
  • On 27 May 2008, at 1:16 PM, Christiaan Hofman wrote:

    > I know, but I never send an (auto)release message to NSUserDefaults
    > or NSUserDefaultsController, ever. Why would I, those are shared
    > objects? That's my point of saying that the object is the shared
    > NSUserDefaultsController, I thought that should be obvious. And it's
    > pretty easy to check that I don't, because I can easily find every
    > single occurrence where I send messages to those object in my code.

    I find that when I have a bug, I am often so convinced that I'm doing
    everything perfectly, that I have to slap myself and say, "well, if
    everything's perfect, you don't have a bug, do you?"

    I find it pays to check whether things are going as well as I think
    they are.

    > Unfortunately I cannot debug this problem, as I don't see the bug. I
    > only see the bug reports from my users. So running with zombies is
    > pointless.

    No, it isn't. An overreleased object pointer will soon have another
    object at the same address, making the pointer look valid to code that
    thinks it is using the old object. It may be that for you, but not for
    your users, the replacement object responds to enough of the old one's
    methods that no crash or log messages (you've checked for those?)
    occur. You are falsely "lucky."

    But if you set NSZombieEnabled, you will catch those bugs, even on
    your "lucky" machine. Just do the test.

    — F
  • On 27 May 2008, at 8:41 PM, Fritz Anderson wrote:

    > On 27 May 2008, at 1:16 PM, Christiaan Hofman wrote:
    >
    >> I know, but I never send an (auto)release message to NSUserDefaults
    >> or NSUserDefaultsController, ever. Why would I, those are shared
    >> objects? That's my point of saying that the object is the shared
    >> NSUserDefaultsController, I thought that should be obvious. And
    >> it's pretty easy to check that I don't, because I can easily find
    >> every single occurrence where I send messages to those object in my
    >> code.
    >
    > I find that when I have a bug, I am often so convinced that I'm
    > doing everything perfectly, that I have to slap myself and say,
    > "well, if everything's perfect, you don't have a bug, do you?"
    >
    > I find it pays to check whether things are going as well as I think
    > they are.
    >

    Sure, but here the situation is really very clear and very much
    contained. The only objects involved are my document and the
    NSUserDefaults and associated classes. So I can easily check every
    single instance of accessing the NSUserDefaults related objects (and I
    did so several times now). And I do know the document object is valid
    at this point, otherwise the stack trace would not be consistently
    like this, it would show crashes just before this point, at least
    sometimes.

    >> Unfortunately I cannot debug this problem, as I don't see the bug.
    >> I only see the bug reports from my users. So running with zombies
    >> is pointless.
    >
    > No, it isn't. An overreleased object pointer will soon have another
    > object at the same address, making the pointer look valid to code
    > that thinks it is using the old object. It may be that for you, but
    > not for your users, the replacement object responds to enough of the
    > old one's methods that no crash or log messages (you've checked for
    > those?) occur. You are falsely "lucky."

    Assuming that n fact it does occur. And I'm pretty much convinced that
    it doesn't. I've never seen it, and in fact I've never seen a single
    crash report form 10.5. All crash reports (from several users) occur
    on 10.4.

    >
    >
    > But if you set NSZombieEnabled, you will catch those bugs, even on
    > your "lucky" machine. Just do the test.
    >
    > — F
    >

    So I don't think it' about being lucky, it's just not happening for
    me. BTW, I tried NSZombieEnabled, and nothing showed up.

    Christiaan