NSMenu setTarget method causes intermittent crashes?

Duncan Champney <[email protected]>
Newsgroups gmane.comp.macosx.devel
Message-ID <[email protected]>
Fellow Cocoa developers,


I think I've found a bug in the Cocoa framework, or at least a gaping  
hole in the documentation. It occurs in a garbage-collected app that  
uses popup menus.

Our app creates several different popup menus.

We have an NSView object that creates an NSMenu object. We then add a  
menu item to the newly created menu, and use the menu item's setTarget  
method to make the view the target of the menu item.

Finally, we invoke the NSMenu class method popUpContextMenu to display  
a popup menu. The whole method (a method of our custom view) looks  
like this:

- (void) popupMenuStartWithEvent:(NSEvent*)p_event
                          onView:(NSView*)p_view
{
    if (p_event && p_view && (!myPopupMenu)) {      
        self.myPopupMenu = [[[JXMenu alloc] initWithTitle:@"Contextual  
Menu"] autorelease];
        //self.myPopupMenu.myPopupMenuView = self;
        NSMenuItem* a_menu_item = [self.myPopupMenu  
insertItemWithTitle:@"Beep" action:@selector(popupMenuAction:)  
keyEquivalent:@"" atIndex:0];
        [a_menu_item setView: self];
        [a_menu_item setTarget:self];
        
        [NSMenu popUpContextMenu:self.myPopupMenu withEvent:p_event  
forView:p_view];
}


This code works fine. I won't post the details of our particular popup  
menu, because they are not relevant.

The problem occurs later, after the NSMenu object and the NSView  
object are deallocated by garbage collection.

SOMETIMES, our app crashes deep in system calls. Looking at the stack  
trace for the crash, the system appears to be deallocating the  
temporary window it uses to manage the popup menu. It seems to cause  
the menu item we create to try to send a message to the view we  
specify as a target in the setTarget call above. However, that  
sometimes takes place after garbage collection has already released  
the view, so the message to the menu item's target ends up trying to  
send a message to a released object, and causes a crash.


Here is the call stack from a crash taken from the XCode debug window:

#0  0x946c3688 in objc_msgSend
#1  0x92608bd1 in CFArrayGetCount
#2  0x908587ac in _recursiveInvalidateCachedVisibleRectValue
#3  0x908583f9 in -[NSView _setSuperview:]
#4  0x90861f86 in -[NSView removeFromSuperview]
#5  0x908db695 in -[NSView removeFromSuperviewWithoutNeedingDisplay]
#6  0x90b3a713 in customMenuItemViewChangeOwningWindow
#7  0x90b39b15 in NSMenuItemCarbonEventHandler
#8  0x94c2f13d in DispatchEventToHandlers
#9  0x94c2e57b in SendEventToEventTargetInternal
#10 0x94c2e3e0 in SendEventToEventTargetWithOptions
#11 0x94c44c52 in HIView::SendOwningWindowChanged
#12 0x94c44ae1 in HIView::NotifySubtreeWindowChanged
#13 0x94c44b03 in HIView::NotifySubtreeWindowChanged
#14 0x94c44b03 in HIView::NotifySubtreeWindowChanged
#15 0x94c44b03 in HIView::NotifySubtreeWindowChanged
#16 0x94c448d0 in HIView::SetWindowRef
#17 0x94cfa66b in _HIViewSetWindow
#18 0x94c6dff1 in DisposeMenuWindow


The fix, it seems,  is to set the menu item's target method to nil  
after the call to popUpContextMenu.

The fixed method looks like this:

  - (void) popupMenuStartWithEvent:(NSEvent*)p_event
                          onView:(NSView*)p_view
{
    if (p_event && p_view && (!myPopupMenu)) {      
        self.myPopupMenu = [[[JXMenu alloc] initWithTitle:@"Contextual  
Menu"] autorelease];
        //self.myPopupMenu.myPopupMenuView = self;
        NSMenuItem* a_menu_item = [self.myPopupMenu  
insertItemWithTitle:@"Beep" action:@selector(popupMenuAction:)  
keyEquivalent:@"" atIndex:0];
        [a_menu_item setView: self];
        [a_menu_item setTarget:self];
        
        [NSMenu popUpContextMenu:self.myPopupMenu withEvent:p_event  
forView:p_view];
        [a_menu_item setView: nil];
        [a_menu_item setTarget:nil];
}

This is an intermittent problem and hard to reproduce, so I am not  
positive that this is the fix.

My guess is that the popup menu code is old carbon (or HI) code, and  
it doesn't "play nicely" with garbage collection.

Has anybody else seen this problem?



Duncan Champney
WareTo
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.