Demystifying iOS Application Crash Logs

This is a blog post by Soheil Moayedi Azarpour, an independent iOS developer. You can also find him on Google+. Have you ever had the following experience as an app developer? Before you submit your app, you perform a lot of testing to make sure your app runs flawlessly. It works fine on your device, […] By Soheil Azarpour.

Leave a rating/review
Save for later
Share
You are currently viewing page 3 of 6 of this article. Click here to view the first page.

Low Memory Crashes

Since low memory crash logs are slightly different than normal crash logs, this tutorial will address them separately. :]

When a low memory condition is detected on an iOS device, the virtual memory system sends out notifications asking applications to release memory. These notifications are sent to all running applications and processes, in an effort to reduce the total amount of memory in use.

If memory usage remains high, the system may terminate background processes to ease memory pressure. If enough memory can be freed, your application will continue to run and no crash report will be generated. Otherwise, your app will be terminated by iOS, and a low memory report will be generated.

In low memory crash logs, there are no stack traces for the application threads. Instead, the memory usage of each process is reported in terms of the number of memory pages. (At the time of writing, a memory page was 4KB in size.)

You will see jettisoned next to the name of any process terminated by iOS to free up memory. If you see it next to your application’s name, it means the application was terminated for using too much memory.

A low memory crash log looks something like this:

Incident Identifier: 30E46451-53FD-4965-896A-457FC11AD05F
CrashReporter Key:   5a56599d836c4f867f6eec76afee451bf9ae5f31
OS Version:          iPhone OS 3.1.3 (7E18)
Date/Time:           2012-10-17 21:39:06.967 -0400

Free pages:        96
Wired pages:       10558
Purgeable pages:   0
Largest process:   Rage Masters

Processes
         Name                 UUID                    Count resident pages
    Rage Masters <cc527ca9b51937c5adbe035fe27a7b12>    9320 (jettisoned) (active)
    mediaserverd <3d3800d6acfff050e4d0ed91cbe2467e>     255
     dataaccessd <13d80b2e707acc91f9aa3ec4c715b9cc>     505
         syslogd <8eddddc00294d5615afded36ee3f1b62>      71
            apsd <32070d91b216d806973c8f1b1d8077a4>     171
       securityd <b9e51062610d27f727c5119b8f80dcdf>     243
         notifyd <591dd4dd804b4b8741f52335ea1fa4ab>    2027
      CommCenter <b4b87526ae086bb62c982f1078f43f81>     189
     SpringBoard <324939a437d1cca1fa4af72d9f5d0eba>    2158 (active)
      accessoryd <8f21c8b376d16e2ccb95ed6d21d8317a>      91
         configd <85efd41aceac34ccc0019df76623c7a9>     371
       fairplayd <a2eaf736b3e07c7c9a2c82e9eb893555>      93
   mDNSResponder <df1cd275e4ad434e0575990e8e1da4cb>     292
       lockdownd <80d2bd44c0bcca273d48ce52010f7e65>    1204
         launchd <a5988245aade809bf77576f1d9de42c5>      72

When you experience a low memory crash in your app, you should investigate memory usage patterns and how your app responds to low memory warnings. You can use the Allocations and Leaks Instruments to discover memory allocation issues and leaks. If you don’t know how to use Instruments to check for memory issues, you might want to check out this tutorial as a starting point.

And don’t forget virtual memory! The Leaks and Allocations Instruments do not track graphics memory. You need to run your application with the VM Tracker Instrument to see your graphics memory usage.

VM Tracker is disabled by default. To profile your application with VM Tracker, click the Instrument, and check the Automatic Snapshotting flag or press the Snapshot Now button manually.

You will investigate a low memory crash log later on in this tutorial.

Exception Codes

Before you dive into some real-life crash scenarios, there’s one more bit about crash log content that warrants a brief introduction: those funny exception codes.

You can find the exception code in the Exception section of the report – section #3 in the above example. There are a few well-known exception codes that you might encounter often.

Usually, an exception code starts with some text, followed by one or more hexadecimal values, which are processor-specific codes that may give you more information on the nature of the crash. From these codes, you can tell if the application crashed due to a programming error, a bad memory access, or if the application was terminated for some other reason.

Here are some of the more common exception codes:

  • 0x8badf00d: Reads as “ate bad food”! (If you squint your eyes and replace the digits with alphabetic characters. :p) This code indicates that an application was terminated by iOS because a watchdog timeout occurred. Basically, the application took too long to launch, terminate, or respond to system events.

  • 0xbad22222: This code indicates that a VoIP application was terminated by iOS because it resumed too frequently.
  • 0xdead10cc: Read this one as “dead lock”! It indicates that an application was terminated by iOS because it held onto a system resource, like the address book database, while running in the background.
  • 0xdeadfa11: Another cute code – read it as “dead fall”! It indicates that an application was force-quit by the user. Per Apple, force quits happen when the user holds down the On/Off button until “slide to power off” appears, then holds down the Home button. As per Apple Documentation, a force quit event results in a 0xdeadfa11 exception code, presumably because the app became unresponsive.

Note: Remember that terminating a suspended app by removing it from the background task list does not generate a crash log. Once an app is suspended, it is eligible for termination by iOS at any time. So no crash log will be generated.

Swimming Time!

All right! You’ve got all the basic background information you need to dive and swim in the pool of crash logs, and fix some nasty bugs! Here is the basic scenario:

You have just started a new job at Rage-O-Rage LLC. The company has a top-selling app in the App Store, Rage Masters.

Your boss, Andy, comes to you and says that to get you started, he has decided to give you a list of different scenarios under which users have claimed the app crashes. Your job is to go through the scenarios and the symbolicated crash logs provided by users, find the bugs in the app, and fix them.

You can download the source code for the app from here.

Note: If you want to regenerate the crash reports for yourself, follow these instructions:

  1. Download the code and open the project file in Xcode.
  2. Connect an authorized iOS device with the correct provisioning profile.
  3. Select the iOS device as the target from the Xcode toolbar – not the Simulator – and build the app.
  4. As soon as you see the default screen (the full-screen image of the app) on the device, hit the stop button in Xcode.
  5. Close Xcode.
  6. Open the app directly on the device.
  7. Test the scenarios, and after you are finished, connect the device and get the crash logs via Xcode.

Scenario 1: Bad Code for Breakfast

From a user email: “Man, your app is a piece of junk! I downloaded it on my iPod Touch, iPhone and my son’s iPod Touch. On all devices, it crashed before running on the first try…”

Another email says, “I downloaded your app and it crashed. Very unhappy…”

Another email is more specific: “I can’t get your app to run. I downloaded it on all of my devices and on my wife’s. On all of them, it crashed on the first launch…”

OK, don’t take this lying down! Do any of these comments give you a hint? Take a look at the crash log:

Incident Identifier: 85833DBA-3DF7-43EE-AF80-4E5C51091F42
CrashReporter Key:   5a56599d836c4f867f6eec76afee451bf9ae5f31
Hardware Model:      iPhone4,1
Process:         Rage Masters [20067]
Path:            /var/mobile/Applications/B2121A89-3D1F-4E61-BB18-5511E1DC150F/Rage Masters.app/Rage Masters
Identifier:      Rage Masters
Version:         ??? (???)
Code Type:       ARM (Native)
Parent Process:  launchd [1]

Date/Time:       2012-11-03 13:37:31.148 -0400
OS Version:      iOS 6.0 (10A403)
Report Version:  104

Exception Type:  00000020
Exception Codes: 0x000000008badf00d
Highlighted Thread:  0

Application Specific Information:
Soheil-Azarpour.Rage-Masters failed to launch in time

Elapsed total CPU time (seconds): 8.030 (user 8.030, system 0.000), 20% CPU 
Elapsed application CPU time (seconds): 3.840, 10% CPU

Thread 0 name:  Dispatch queue: com.apple.main-thread
Thread 0:
0   libsystem_kernel.dylib        	0x327f2eb4 mach_msg_trap + 20
1   libsystem_kernel.dylib        	0x327f3048 mach_msg + 36
2   CoreFoundation                	0x36bd4040 __CFRunLoopServiceMachPort + 124
3   CoreFoundation                	0x36bd2d9e __CFRunLoopRun + 878
4   CoreFoundation                	0x36b45eb8 CFRunLoopRunSpecific + 352
5   CoreFoundation                	0x36b45d44 CFRunLoopRunInMode + 100
6   CFNetwork                     	0x32ac343e CFURLConnectionSendSynchronousRequest + 330
7   Foundation                    	0x346e69ba +[NSURLConnection sendSynchronousRequest:returningResponse:error:] + 242
8   Rage Masters                  	0x000ea1c4 -[RMAppDelegate application:didFinishLaunchingWithOptions:] (RMAppDelegate.m:36)
9   UIKit                         	0x37f30ad4 -[UIApplication _handleDelegateCallbacksWithOptions:isSuspended:restoreState:] + 248
10  UIKit                         	0x37f3065e -[UIApplication _callInitializationDelegatesForURL:payload:suspended:] + 1186
11  UIKit                         	0x37f28846 -[UIApplication _runWithURL:payload:launchOrientation:statusBarStyle:statusBarHidden:] + 694
12  UIKit                         	0x37ed0c3c -[UIApplication handleEvent:withNewEvent:] + 1000
13  UIKit                         	0x37ed06d0 -[UIApplication sendEvent:] + 68
14  UIKit                         	0x37ed011e _UIApplicationHandleEvent + 6150
15  GraphicsServices              	0x370835a0 _PurpleEventCallback + 588
16  GraphicsServices              	0x370831ce PurpleEventCallback + 30
17  CoreFoundation                	0x36bd4170 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 32
18  CoreFoundation                	0x36bd4112 __CFRunLoopDoSource1 + 134
19  CoreFoundation                	0x36bd2f94 __CFRunLoopRun + 1380
20  CoreFoundation                	0x36b45eb8 CFRunLoopRunSpecific + 352
21  CoreFoundation                	0x36b45d44 CFRunLoopRunInMode + 100
22  UIKit                         	0x37f27480 -[UIApplication _run] + 664
23  UIKit                         	0x37f242fc UIApplicationMain + 1116
24  Rage Masters                  	0x000ea004 main (main.m:16)
25  libdyld.dylib                 	0x3b630b1c start + 0

Did you find the problem? The exception code is 0x000000008badf00d, and right after that, the report says:

Application Specific Information:
Soheil-Azarpour.Rage-Masters failed to launch in time

Elapsed total CPU time (seconds): 8.030 (user 8.030, system 0.000), 20% CPU 
Elapsed application CPU time (seconds): 3.840, 10% CPU

This means that the app failed to launch in time, and the iOS watchdog terminated the app. Cool! You found the reason, but why (and more importantly, where) is it happening?

Look further down in the log. The convention is to read the backtrace log from the bottom up. The lowest frame (frame 25: libdyld.dylib) is the first call, then frame 24, Rage Masters, main (main.m:16) is called from there, and so on.

You are interested in frames that are related to your app’s code. So ignore system libraries and frameworks. The next line relevant to your code is:

8    Rage Masters    0x0009f244 -[RMAppDelegate application:didFinishLaunchingWithOptions:] (RMAppDelegate.m:35)

The app failed in application:didFinishLaunchingWithOptions:, on line 35 in RMAppDelegate (RMAppDelegate.m:35). Open Xcode and take a look at that line:

NSData *directoryData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];

Yep, there it is! A synchronous call to a web service?! On the main thread?! In application:didFinishLaunchingWithOptions:?!! Who wrote this code?!

Network calls on the main thread makes kittens sad.

Network calls on the main thread makes kittens sad.

Anyway, it’s your job to fix it. This call should be asynchronous and, even better, executed from another part of the application, after application:didFinishLaunchingWithOptions: has returned YES.

It might require more extensive changes to move the call elsewhere. So for the moment, just take care of the code so that it doesn’t crash. You can always go back and implement a better design later. Replace the line of offending code from above (and the three lines following it) with an asynchronous version:

[NSURLConnection sendAsynchronousRequest:request
                                           queue:[NSOperationQueue mainQueue]
                               completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
         {
             NSURL *cacheDirectory = [[[NSFileManager defaultManager] URLsForDirectory:NSUserDirectory inDomains:NSCachesDirectory] lastObject];
             NSURL *filePath = [NSURL URLWithString:kDirectoryFile relativeToURL:cacheDirectory];
             [data writeToFile:[filePath absoluteString] atomically:YES];
         }];

Contributors

Over 300 content creators. Join our team.