The Problem
I'm receiving crash reports from users that look like this:
Code Type: X86-64 (Native)
Parent Process: launchd [223]
Date/Time: 2012-03-22 11:28:33.087 +0800
OS Version: Mac OS X 10.7.3 (11D50)
Report Version: 9
Crashed Thread: 0 Dispatch queue: com.apple.main-thread
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: 0x000000000000000d, 0x0000000000000000
VM Regions Near 0:
-->
__TEXT 000000010c202000-000000010c29c000 [ 616K] r-x/rwx SM=COW /Applications/CodeKit.app/Contents/MacOS/CodeKit
Application Specific Information:
objc_msgSend() selector name: release
objc[22113]: garbage collection is OFF
Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0 libobjc.A.dylib 0x00007fff904f5390 objc_msgSend_vtable14 + 16
1 com.apple.Foundation 0x00007fff8f664137 empty + 61
2 com.apple.Foundation 0x00007fff8f666c10 dealloc + 24
3 com.apple.Foundation 0x00007fff8f666bd1 -[NSConcreteMapTable dealloc] + 64
4 com.apple.AppKit 0x00007fff892bc52c -[_NSDisplayOperation dealloc] + 84
5 com.apple.CoreFoundation 0x00007fff8fdc7ca0 CFRelease + 176
6 com.apple.CoreFoundation 0x00007fff8fdf0742 -[__NSArrayM removeObjectAtIndex:] + 434
7 com.apple.AppKit 0x00007fff892bc408 -[_NSDisplayOperationStack exitDisplayOperationForWindow:] + 417
8 com.apple.AppKit 0x00007fff892be2fc -[NSView _displayRectIgnoringOpacity:isVisibleRect:rectIsVisibleRectForView:] + 7136
9 com.apple.AppKit 0x00007fff892b6429 -[NSView displayIfNeeded] + 1676
10 [SEE DISCUSSION BELOW]
Discussion
Lines 10 and below vary wildly between reports (and hence are unrelated to the crash). However, the sequence from lines 1 to 9 is always the same. Every crash contains this exact sequence. I've googled "_NSDisplayOperationStack" and I've found similar crash reports for dozens of apps (including well-known ones such as Omni apps and Apple's Motion.)
What I Need
Because the crash is coming from Core Foundation, I have no idea where to begin looking for the problem. It seems to be deep inside Cocoa's private view-drawing machinery. Worse still, I can't replicate the crash on my machine at all, so I can't trace it with Instruments. But I've received many reports with the pattern above, so I know it's a problem. Worse STILL, the users can't even reproduce the crash reliably -- it's completely intermittent.
I'm hoping the above sequence looks familiar to someone and they can give me guidance on where to start looking for the problem. Thank you.
I posted this same question over at the Apple Developer forums and one engineer told me that it looked like the stack trace had to do with concurrent view drawing, which is a feature that was introduced in 10.6.
I went through all of my NIB files and found two NSButton instances that were set to draw concurrently --- this was not intentional; I must have checked that box by accident at some point.
I disabled the concurrent drawing for both of them and this crash has magically disappeared.
In some cases disabling concurrent drawing for just some buttons doesn't help. I got the same error as the author's ("_NSDisplayOperationStack underflow raised during heart beat."). Lucky there is a master switch in a window that disables all concurrent drawing for one window:
[self.window setAllowsConcurrentViewDrawing:NO];
Also opening the the window via a block executed on the main queue helped:
dispatch_async(dispatch_get_main_queue(), ^{
if(nil == self.someWindowController) {
self.someWindowController = [[[SomeWindowController alloc] initWithWindowNibName:#"SomeWindowController"] autorelease];
}
[self.someWindowController.window makeKeyAndOrderFront:self];
});
Showing the window from within a block just postpones the execution a little bit but for my application, some additional window opening via menu shortcut, a combination of the two were the only thing working.
Related
Getting this weird crash after updating to Mojave.
Not doing anything special, just creating an NSWindow and calling orderFrontRegardless
Always worked fine before.
1 libsystem_platform.dylib 0x00007fff6610ab5d _sigtramp + 29
2 ??? 0x0000000000000000 0x0 + 0
3 CoreFoundation 0x00007fff39b00bb6 __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 12
4 CoreFoundation 0x00007fff39b00b30 ___CFXRegistrationPost_block_invoke + 63
5 CoreFoundation 0x00007fff39b00a9a _CFXRegistrationPost + 404
6 CoreFoundation 0x00007fff39b08f48 ___CFXNotificationPost_block_invoke + 87
7 CoreFoundation 0x00007fff39a71994 -[_CFXNotificationRegistrar find:object:observer:enumerator:] + 1642
8 CoreFoundation 0x00007fff39a70d47 _CFXNotificationPost + 732
9 Foundation 0x00007fff3bdab217 -[NSNotificationCenter postNotificationName:object:userInfo:] + 66
10 AppKit 0x00007fff3720538b -[NSWindow _setFrameCommon:display:stashSize:] + 3090
11 AppKit 0x00007fff37204766 -[NSWindow _setFrame:display:allowImplicitAnimation:stashSize:] + 192
12 AppKit 0x00007fff3720469f -[NSWindow setFrame:display:] + 51
13 AppKit 0x00007fff3727aca9 -[NSWindow _reallyDoOrderWindowAboveOrBelow:relativeTo:findKey:forCounter:force:isModal:] + 1336
14 AppKit 0x00007fff372792a0 -[NSWindow _doOrderWindow:relativeTo:findKey:forCounter:force:isModal:] + 283
15 AppKit 0x00007fff37a0dce9 -[NSWindow orderFrontRegardless] + 40
Code (it's a console app):
NSWindow *window = [[NSWindow alloc] initWithContentRect:windowRect
styleMask:windowStyle
backing:NSBackingStoreBuffered
defer:NO];
// Since Snow Leopard, programs without application bundles and Info.plist
// files don't get a menubar and can't be brought to the front unless the
// presentation option is changed
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
[NSApp activateIgnoringOtherApps:YES];
[window makeKeyAndOrderFront:nil];
How do you initialize the app? Do you have NSApplication initialized before using AppKit?
Something like these steps should be necessary in main.m:
#autoreleasepool {
NSApplication* application = NSApplication.sharedApplication;
AppDelegate* delegate = [[AppDelegate alloc] init];
application.delegate = delegate;
[application run];
}
Also your delegate might be getting deallocated, since NSApp holds a weak reference to it.
You indicated that you were dereferencing an uninitialized pointer. But, I don't have enough information from the report you posted to know if this was (perhaps by luck) null, or just garbage memory. I'll assume that at some point you crashed with an EXC_BAD_ACCESS (signal equivalent is SIGBUS or SIGSEGV, depending).
The critical bit of information here was that you had a signal handler installed.
Signal handlers generally (but not always) run on the crashing thread using the same stack. The kernel injects the handler using that _sigtramp function. Upon signal delivery, current stack state contained the information you needed to track down the bad memory access. But, your signal handler was invoked instead. So it ran, mutating the stack as it did.
Then, your signal handler completed somehow. It is possible to configure a signal handler using sigaction such that the process state is restored to the moment just before the crashing event. I'm not sure how your signal handler was configured. But, ultimately, I'm going to assume that the process was allowed to exit.
At this point, Apple's ReportCrash would have been triggered, and would capture backtraces for all threads in whatever state your signal handler left them. This is critical, because that's not necessarily the crashing state.
Adding complexity, backtrace_symbols_fd is not at all safe to use from a signal handler. Async safety is challenging, and running code from a signal handler is highly difficult to get right. There are very few things you can do safely. I'm pretty sure, additionally, that backtrace_symbols_fd allocates memory. So, if your crash was in the memory allocator somewhere, and it sounds like it was, you were definitely at risk for a deadlock. Judging by the backtrace, it seems like that's exactly what might have happened. Check out man sigaction for some details.
Worse, unwinding the stack over a signal handler frame is particularly challenging because of the magic the kernel does to run your handler. That's why that ??? frame is in there.
A summary:
Without a signal handler installed, Apple's ReportCrash would have produced a correct (and likely helpful) backtrace for the crashing thread.
The stack trace you've included isn't great, but it's hard to know exactly why.
It appears that backtrace_symbols_fd didn't do a good job of unwinding, possibly due to it being inappropriate to use from a signal handler, possibly because it isn't backed by a good-enough stack unwinding mechanism for this situation. But, without more information, it's difficult for me to know. I am surprised the the top frame was _sigtramp, though. That doesn't make a lot of sense. It makes me think something might have been going wrong in the signal handler itself. It is possible to crash a second time in your handler.
Apple's backtraces (generated by ReportCrash, backtrace_symbols_fd, or NSThread's callStackReturnAddresses, for example) can definitely be trusted, provided you're careful to use them in safe contexts.
Turns out I had a serious memory bug in a completely different place not even mentioned in the backtrace.
I was dereferencing an uninitialised pointer.
This is the second time it happens.
Do no trust Apple's backtraces when debugging memory errors.
Even with libgmalloc.
I get invariably this error when I close the last window of my app:
Application Specific Information: objc_msgSend() selector name:
respondsToSelector: objc[42729]: garbage collection is OFF
Thread 0 Crashed:: Dispatch queue: com.apple.main-thread 0
libobjc.A.dylib 0x00007fff8cc9a150 objc_msgSend_vtable5
+ 16 1 com.apple.AppKit 0x00007fff8fbca814 -[NSApplication supplementalTargetForAction:sender:] + 63 2 com.apple.AppKit 0x00007fff8fab91e4
_objectFromResponderChainWhichRespondsToAction + 155 3 com.apple.AppKit 0x00007fff8fab8feb
_NSTargetForSendAction + 3255 4 com.apple.AppKit 0x00007fff8fab832f -[NSApplication targetForAction:to:from:] + 682 5
com.apple.AppKit 0x00007fff8fab7e00 -[NSMenu
_enableItem:] + 403
I confess that the document nib has two windows. I want the "auxiliary window" to be closed and deallocated when the main window is closed. How should I do? Maybe these errors com from hereā¦ I'm using Core Data and ARC.
Regards
I found something which seems to solve the problem. But I don't understand what's happening and I really dislike this.
In IB, the file's owner has a "window" outlet who points to the document window; but there is no #property NSWindow window; in the default code of the NS(Persistent)Document.
I had to make a panel a "child window" of the doc's main window, so I add a #property NSWindow mainWindow. The new "mainWindow" outlet points to the same window as the "window" outlet.
And suddenly no more crash, no more zombie. What happened? I'm baffled.
After reflexion: I have added a pointer to the document window, so the ARC counter never reaches zero. I suppose I had a missing reference somewhere to the _window of the NSDocument, which is now balanced by my outlet.
In my app, I have am receiving multiple memory leaks. The object is Malloc 48 bytes, and it always originates from the responsible caller strdup. The history of the object only shows it being Malloced, and no other retains or releases. The stacktrace doesn't show any of my code. The only bits of relevance that I can pick out are:
10 UIKit _UIGestureRecognizerSendActions
9 UIKit -[UIScrollView handlePan:]
8 UIKit -[UIScrollView _endPanWithEvent:]
7 UIKit -[UIScrollView(Static) _startTimer:]
6 CoreFoundation CFNotificationCenterAddObserver
5 CoreFoundation _CFXNotificationRegisterObserver
4 libnotify.dylib notify_register_dispatch
3 libnotify.dylib notify_register_mach_port
2 libnotify.dylib token_table_add
1 libsystem_c.dylib strdup
0 libsystem_c.dylib malloc
It seems to occur whilst scrolling on a map view, but I am unsure how to proceed as none of my code is referenced in the stack. How should I proceed in diagnosing this leak?
If any further information is required, please let me know.
Regards,
Nick
If it is "only" 48 bytes, all evidence points to frames in the system frameworks (i.e. the allocation is never exposed to your code), and there are not 10s of thousands of 'em, then I (a) wouldn't worry about it too much, but I would (b) immediately file a bug via http://bugreport.apple.com/
Attach a binary of your application and instructions as to how to reproduce the issue.
I think I've confirmed it was introduced in 5.1. I am able to duplicate the memory leak every time in my app by pressing the home button when my app is active with a UIScrollView as the active view using iPhone simulator 5.1. The same test running on iPhone simulator 5.0 does not reproduce the error.
Hope this helps
Just to confirm that this is indeed a reoccurring issue and not just you having a problem. I have seen this happen in Table scrolling as well as UIScrollView. I've tested it in simulator, as well as profiling the release versions on an iPad. Seems to be a common problem in 5.1 but I have yet to hear of a fix. And I do agree, 48bytes at every scroll could potentially become an issue.
it might be caused by performselectorinbackground, call it inside of #autoreleasepool{} block
I recently received a crash report from itunes connect. Actually it's the only crash report I got from thousands of users, yet. It's an iPod4,1 device. Interesting parts are:
Date/Time: 2012-02-27 22:53:27.596 +0800
OS Version: iPhone OS 5.0.1 (9A405)
Report Version: 104
Exception Type: EXC_CRASH (SIGABRT)
Exception Codes: 0x00000000, 0x00000000
Crashed Thread: 0
Last Exception Backtrace:
0 CoreFoundation 0x338958bf __exceptionPreprocess + 163
1 libobjc.A.dylib 0x303891e5 objc_exception_throw + 33
2 UIKit 0x31259749 -[UIViewController mutableChildViewControllers] + 1
3 UIKit 0x31259349 -[UINavigationController pushViewController:animated:] + 37
4 MyApp 0x000081e5 -[MyListController tableView:didSelectRowAtIndexPath:] (MyListController.m:207)
5 UIKit 0x312d3565 -[UITableView _selectRowAtIndexPath:animated:scrollPosition:notifyDelegate:] + 945
6 UIKit 0x3134bce7 -[UITableView _userSelectRowAtPendingSelectionIndexPath:] + 159
It seems that the crash occurs when a row from a table view is selected, and a new view controller is pushed into navigation. According to my code, the new view controller is created already, so the crash occurred in UINavigationController.
It doesn't look like the fault of the code I wrote. And I wonder if I'm correct on this? How do I debug this problem?
It sounds like the user got a low-memory warning. UINavigationControllers will retain their views, whereas tabbed ones will pop off the invisible ones. However, the low memory code is still getting called. Check your warning handlers prior to reaching that spot. Also, test by hitting "Simulate Memory Warning" under the hardware menu at all entry and exit points.
http://forums.macrumors.com/showthread.php?t=876419 shows a mess of what happens when you don't.
iphonedevsdk.com/forum/iphone-sdk-development/14225-uinavigationcontrollers-and-didreceivememorywarning.html has a nice comment or so on how to handle this.
I'm betting your view controller loads something and caused the memory warning. Ensure the user can't just stack tons of items on top of each other, and make sure your app is profiled to remove as many leaks as necessary to keep the app up.
The above may not be on the mark, but should be related.
Final note, don't use ARC. Something that disallows calling superclass functions is bound to screw up. If you understand bridging Core Foundation, then perhaps ARC is fine. I personally avoid it at all costs b/c memory becomes randomly handled by Apple's under-the-hood. I've seen their stuff fail way too much
I got it! I had the same problem too and in your code it looks like that a button is pressed, which causes the crash!
Last Exception Backtrace:
0 CoreFoundation 0x338958bf __exceptionPreprocess + 163
1 libobjc.A.dylib 0x303891e5 objc_exception_throw + 33
2 UIKit 0x31259749 -[UIViewController mutableChildViewControllers] + 1
3 UIKit 0x31259349 -[UINavigationController pushViewController:animated:] + 37
4 MyApp 0x000081e5 -[MyListController tableView:didSelectRowAtIndexPath:] (MyListController.m:207)
5 UIKit 0x312d3565 -[UITableView _selectRowAtIndexPath:animated:scrollPosition:notifyDelegate:] + 945
6 UIKit 0x3134bce7 -[UITableView _userSelectRowAtPendingSelectionIndexPath:] + 159
Here is my suggestion:
Two things to solve a SIGABRT:
1) SIGABRT happens due to a runtime exception that isn't caught. When this happens there is some info written to the debugger console or the device console that explains the exact reason for the exception. You haven't shown us this text. It starts "Terminating application due to ..."
Show us that text.
2) If you run your app in the debugger and set a breakpoint on the exception throw function the app will stop when the exception is thrown and this will usually be enough to figure it out. Go to the debugger breakpoint pane and at the bottom left is a control that when clicked allows you to set an exception breakpoint.
A user has sent in a crash report with the stack trace listed below (I have not been able to reproduce the crash myself, but every other crash this user has reported has been a valid bug, even when I couldn't reproduce the effect). The application is a reference-counted Objective-C/Cocoa app.
If I am interpreting it correctly, the crash is caused by attempting to send a drawerDidOpen: message to a deallocated object. The only object that should be receiving drawerDidOpen: is the drawer's delegate object (nowhere does any object register to receive drawer notifications), and the drawer's delegate object is instantiated via the XIB/NIB file, wired to the delegate outlet of the drawer, and not referenced anywhere else.
Given that, how can I protect against the delegate getting dealloc'd before the drawer notification? Or, alternately, what have I misinterpreted that might be causing the crash?
Crash log/stack trace:
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: KERN_INVALID_ADDRESS at 0x0000000000000010
Crashed Thread: 0 Dispatch queue: com.apple.main-thread
Application Specific Information:
objc_msgSend() selector name: drawerDidOpen:
Thread 0 Crashed: Dispatch queue: com.apple.main-thread
0 libobjc.A.dylib 0x00007fff8272011c objc_msgSend + 40
1 com.apple.Foundation 0x00007fff87d0786e _nsnote_callback + 167
2 com.apple.CoreFoundation 0x00007fff831bcaea __CFXNotificationPost + 954
3 com.apple.CoreFoundation 0x00007fff831a9098 _CFXNotificationPostNotification + 200
4 com.apple.Foundation 0x00007fff87cfe7d8 -[NSNotificationCenter postNotificationName:object:userInfo:] + 101
5 com.apple.AppKit 0x00007fff8512e944 _NSDrawerObserverCallBack + 840
6 com.apple.CoreFoundation 0x00007fff831d40d7 __CFRunLoopDoObservers + 519
7 com.apple.CoreFoundation 0x00007fff831af8c4 CFRunLoopRunSpecific + 548
8 com.apple.HIToolbox 0x00007fff839b8ada RunCurrentEventLoopInMode + 333
9 com.apple.HIToolbox 0x00007fff839b883d ReceiveNextEventCommon + 148
10 com.apple.HIToolbox 0x00007fff839b8798 BlockUntilNextEventMatchingListInMode + 59
11 com.apple.AppKit 0x00007fff84de8a2a _DPSNextEvent + 708
12 com.apple.AppKit 0x00007fff84de8379 -[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:] + 155
13 com.apple.AppKit 0x00007fff84dae05b -[NSApplication run] + 395
14 com.apple.AppKit 0x00007fff84da6d7c NSApplicationMain + 364
15 (my app's identifier) 0x0000000100001188 start + 52
edit: To clarify: This crash happened once in thousands or maybe tens of thousands of virtually-identical usage scenarios. I don't retain/release/alloc/dealloc/anything-memory-management the delegate object anywhere in my code; I don't register any object for any drawer notifications of any kind in my code; my code has no variables (nor ivars) pointing to the delegate object.
What it looks like to me is that when the NIB was unloaded (as in whatever the Cocoa system does when the document window gets closed), somehow the drawer's delegate object was dealloc'd before the drawer object itself, but the Cocoa system is supposed to prevent that from happening (and seems to handle it correctly in the vast majority of cases).
The delegate has been released to the point of deallocation without first being unregistered from the notification center (in this case, the delegation is through the notification center, not directly).
An easy fix is to call NSNotificationCenter's -removeObserver: method from your delegate's -dealloc method.
Check the backtrace -- it is through the notification center that the crash happens. Most likely, when the class is connected via setDelegate: (via the NIB file), it is done so as a notification observer.
Regardless, the relationship between notification center and your object is the same as between the object in IB and your object; weak. That is, there is no retain and, thus, your delegate is being freed too early (or, alternatively, you are over-releasing the object somewhere).
In any case, you need to make sure your delegate is retained by something somewhere for the duration of its usefulness.