Xcode doesn't show the line that causes a crash
Asked Answered
E

5

131

Every time my app crashes Xcode highlights the UIApicationMain() call in the main() function as the line that caused the crash. In some cases that used to be normal (segmentation fault for example) but the crash I am trying to deal with is a simple SIGABRT with detailed information logged in the console:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFDictionary setObject:forKey:]: attempt to insert nil value (key: Date)'

Xcode used to show the line just right with older SDKs but since i upgraded to Xocde 4.2 that changed. It is pretty obvious that Xcode knows exactly what caused the crash (or could know), but its still not showing the actual line. Is there any fix or workaround for this?

Equuleus answered 9/10, 2011 at 11:2 Comment(3)
Are you compiling for Release? If so try setting the scheme to Debug.Farrahfarrand
It could also be that some xib is bad causing the program to crash in a place out of your own source code, thus, not showing any file. The error describes a problem for a dictionary key named "Date"Farrahfarrand
Apple should hire more testers ;)Christianize
L
307

You should also ensure that you have breakpoints set for all exceptions. This will cause Xcode to stop at the line where the exception is occurring. Do the following [in Xcode 4]:

  1. In the Project Navigator on the left side of Xcode, click on the breakpoint navigator (almost all the way to the right hand side of the top button bar. The icon looks like a fat right arrow).

  2. At the bottom of the navigator, click the "+" button.

  3. Click "Add Exception Breakpoint".

  4. A new breakpoint will be created. It should be configured as needed but you can tweak its behavior.

  5. Run your project and reproduce the exception.

Also you mentioned that you linked to some 3rd party libraries/frameworks. If the exception is occurring within those frameworks then you are going to have a hard time since the code is compiled and Xcode can't actually show you the line that caused the exception. If this is the case and you are certain you are using the libraries correctly, then you should file a bug report to the maintainers of those libraries.

Lora answered 9/10, 2011 at 12:42 Comment(15)
No, choose "On Throw", else it will catch the breakpoint on main.Haulm
I am a noob and developed almost a month without this... this changes my life.Kinnikinnick
My friend registered for a S.O. account just to upvote this post.Tripterous
this is called half assing on apples part in my bookPhosphorylase
Did this but still can't find where it called length on a null :(Filigreed
This works, but the downside is it not longer outputs details of the exception in the debug console. So I can turn OFF this breakpoint, and see details and trace of the exception but not WHERE it happened, or turn it ON to see where it happened, but with not WHY. Anyone know how to have both?Alpenstock
This answer is the most amazing thing I've seen for a while, thanks!Mariko
Nice and simple! This works perfectly on Xcode 6.1 also.Hooker
@GabrielJensen pressing the continue program execution button (maybe more than once) will give you the exception details just like when the breakpoint is not set.Lichter
Why should I have to "reproduce the exception"???? That's completely unreasonable and a waste of my time. Tell me the first time it crashes. There are crashes where reproducing are VERY non trivial. Dear Xcode, What a great IDE you are. If you have a bug, all I have to do is restart you and there's a 50% chance the bug is fixed.Lucinalucinda
It does not work with fatal error: unexpectedly found nil while unwrapping an Optional valueIsidore
I tested this solution in Xcode 7 and it worked perfectly. But shouldn't this be done automatically by Xcode?Jactitation
You absolute legend! I can't believe how long I've spent debugging apps without knowing this.Gilboa
Incredible! This used to be default behaviour, but I've wasted years throwing NSLog everywhere to track down the point at which crashes occur. This has changed everything :DBlether
Lifesaver! I removed all breakpoints at once, took the default exception handler with me!Olsewski
R
28

Simply follow the instructions on this StackOverflow answer:

Enable Zombies

Basically, you just need to "Enable Zombies". Then Xcode should break at whichever line caused the problem.

enter image description here

(It is absolutely shocking that, even in 2017, Xcode still has this turned off by default. Why would you not want to see the line that caused the problem ? And "Enable Zombie Objects" ?! Really ?! Do the Xcode authors really believe that this is a useful name, which would make any kind of sense to new developers ? It is depressing how poor Xcode's rating is, year after year, in the App Store. No one is listening...)

Raffish answered 2/5, 2016 at 5:17 Comment(2)
Xcode is the worst programming environment I used so far.Dactyl
What I find interesting (as a Visual Studio developer) is how many Xcode developers I've met, who insist that Xcode is the best environment they've ever used. Logical, friendly and helpful.. but with a few quirks. Even now, in November 2019, Xcode has an App Store rating of 3.1, with most people giving it 5-stars or 1-star. No one is listening....Raffish
N
10

Edit the current scheme and enable NSZombieEnabled, MallocStackLogging, and guard malloc. Then, when your App crashes, type this in the gdb console:

(gdb) info malloc-history 0x543216

Replace 0x543216 with the address of the object that caused the NSInvalidArgumentException and it should give you a much more useful stack trace, showing the lines of your code that are causing the crash.

Newcomer answered 10/10, 2011 at 2:31 Comment(2)
I tried this, and was thrown the error: 'info' is not a valid command. Any advice?Talcahuano
@EliGregory make sure your debugger is set to gdb and not the default lldb. You can change it in the Edit Scheme menu under the run section.Newcomer
I
2

I have seen this behavior in heavily optimized code; checking,tweaking your target's optimization level and those of 3rd party libs may help. (LLVM 3.0 Optimization level setting)

Are you generating debug symbols?

Inebriety answered 10/10, 2011 at 2:26 Comment(1)
Agreed. If you are trying to debug then the optimization level needs to be set to 0 (No Optimization) in your build settings.Lora
T
1

I wrote code to generate a crash of index out of bound. Following is the exception thrown.

2017-01-07 04:02:57.606 testABC[1694:52966] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSSingleObjectArrayI objectAtIndex:]: index 1 beyond bounds [0 .. 0]'
*** First throw call stack:
(
    0   CoreFoundation                      0x000000010e85cd4b __exceptionPreprocess + 171
    1   libobjc.A.dylib                     0x000000010e2be21e objc_exception_throw + 48
    2   CoreFoundation                      0x000000010e8b5c2f -[__NSSingleObjectArrayI objectAtIndex:] + 111
    3   testABC                             0x000000010dce962d -[ViewController ComplexFunction] + 61
    4   testABC                             0x000000010dce95db -[ViewController thirdFunction] + 43
    5   testABC                             0x000000010dce959b -[ViewController secondFunction] + 43
    6   testABC                             0x000000010dce955b -[ViewController firstFinction] + 43
    7   testABC                             0x000000010dce96c2 -[ViewController viewDidAppear:] + 50
    8   UIKit                               0x000000010ee28a6c -[UIViewController _setViewAppearState:isAnimating:] + 945
    9   UIKit                               0x000000010ee2b7da __64-[UIViewController viewDidMoveToWindow:shouldAppearOrDisappear:]_block_invoke + 42
    10  UIKit                               0x000000010ee29ac4 -[UIViewController _executeAfterAppearanceBlock] + 86
    11  UIKit                               0x000000010ec8d77c _runAfterCACommitDeferredBlocks + 653
    12  UIKit                               0x000000010ec7a273 _cleanUpAfterCAFlushAndRunDeferredBlocks + 566
    13  UIKit                               0x000000010ec9d757 __84-[UIApplication _handleApplicationActivationWithScene:transitionContext:completion:]_block_invoke_2 + 194
    14  CoreFoundation                      0x000000010e8016ac __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 12
    15  CoreFoundation                      0x000000010e7e66f4 __CFRunLoopDoBlocks + 356
    16  CoreFoundation                      0x000000010e7e5e65 __CFRunLoopRun + 901
    17  CoreFoundation                      0x000000010e7e5884 CFRunLoopRunSpecific + 420
    18  GraphicsServices                    0x00000001126d9a6f GSEventRunModal + 161
    19  UIKit                               0x000000010ec80c68 UIApplicationMain + 159
    20  testABC                             0x000000010dce99df main + 111
    21  libdyld.dylib                       0x000000011174968d start + 1
    22  ???                                 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException

If you read carefully the First Throw call stack

0   CoreFoundation              0x000000010e85cd4b __exceptionPreprocess + 171
1   libobjc.A.dylib             0x000000010e2be21e objc_exception_throw + 48

0 and 1 are the system processes after crash.

 2   CoreFoundation             0x000000010e8b5c2f -[__NSSingleObjectArrayI objectAtIndex:] + 111

2 is the line which caused the exception.

3   testABC                     0x000000010dce962d -[ViewController ComplexFunction] + 61

3 tells you that Class name (ViewController) and function naem (ComplexFunction) in which exception was thrown.

Treacherous answered 6/1, 2017 at 23:26 Comment(2)
Errr, okay. You're absolutely right, but is this friendly ? In any modern (1990s onwards) development environment, when an exception occurs, you are taken to the line which caused the problem. Whereas Xcode... well... gives you a stack trace like this. Even Turbo Pascal wasn't this outdated !!!Raffish
It's ridiculous that the company that's supposedly known for the "best user experience" doesn't realize that all developers for the last 20 years are accustomed to seeing the line number where an exception is thrown and NOT IN ASSEMBLER. Am I going insane? Every language I've ever worked with my entire life gives line numbers. Even C or C++.Newson

© 2022 - 2024 — McMap. All rights reserved.