The introduction

IOS development we will encounter in the program exit abnormal situation, if they are in the process of debugging, possibly through a breakpoint or print the key information to debug, but for some complex modules will not collapse of abnormal now, this way is sometimes difficult to locate the problem, but also for online application have been issued, this way is powerless.

Usually, Crash can be divided into two types. One is caused by a system memory error that triggers EXC_BAD_ACCESS, and the program accesses the wrong memory address during running. The other is caused by a signal exception that cannot be handled, which causes the program to send SIGABRT signal to itself and Crash. Here is my usual use of crash processing methods, to share with you.


Part 1: Crash caused by memory error

➸ 1.1 Possible causes

  1. A memory address not belonging to this process was accessed.
  2. Access freed memory (repeatedly freeing freed memory).

IOS development uses a reference counting mechanism for memory management for objects that inherit from NSObject. For non-NSObject objects, reference counting does not work. You need to manage memory usage and recycling yourself. The principle of reference counting is that when an object is retained once, its reference count is retainCount +1, it is marked release once, retainCount -1, and when retainCount is 0 the object is released.

When developing with manual reference counting (MRC), the developer explicitly calls retain or release. After iOS5, apple implemented automatic reference counting (ARC). Developers do not have to explicitly call retain or release, but the compiler automatically adds them. This makes it easier for developers and makes it harder to locate errors when memory problems occur.


➸ 1.2 Common handling methods

1.2.1 Adding Xcode global exception Breakpoints

① Change the navigator view to breakpoint navigator view:


② Click the + sign in the lower left corner and select The Exception Breakpoint option.


③ Exception breakpoints can edit many functions, such as executing scripts, outputting logs, choosing to handle only Objective-C exceptions, and so on.

The next time we run a program that crashes, the program will automatically stop at the broken code, so we can find the problem.


1.2.2 Debugging zombie Objects

Global exception breakpoints usually pinpoint the cause of a crash to specific code. However, if the crash is not on the current call stack, the system can only tell us the crash address, not the specific code, so we can’t fix the error. Something like this:

 

In this case we can try to find the problem through Xcode’s Zombie object debugging.

Select Xcode-> Preferencese from the behavior TAB, and set the output information to output more information during debugging.


② In the Product > Scheme > Edit Scheme menu, tick the three items in the red circle:


③ After this option is enabled, when the program is running, if it accesses the released object, it will give accurate location information, which can help determine the problem.

The principle is that when the object is released (retainCount 0), a built-in Zombie object is used instead of the original released object. No matter what message (function call) is sent to the object, an exception is raised, throwing debugging information.

Note: Remember to turn this feature off after the problem has been fixed! The program memory usage is abnormal.


(4) Run the mallochistory command on the terminal to print the call information, for example, “mallochistory 30495 0x60005ef76FD0 “, where 30495 is the PID of the process. The PID can be viewed from the log in the Xcode console, or from the activity monitor, and from this log, you can roughly determine the location of the error code.

Code similar to the following prompts you to locate the error based on some key information.





1.2.3 using NSSetUncaughtExceptionHandler processing

Before the two ways, the online APP powerless, so to speak, ok, iOS provides a context where the exception happened, in dealing with the API, NSSetUncaughtExceptionHandler, when we start the program can add such a Handler, Such procedures can be abnormal when this part of the information for the necessary processing, timely feedback to the developer. It is important to note that the use of NSSetUncaughtExceptionHandler collapse can be used to handle exceptions, crash reporting system will use NSSetUncaughtExceptionHandler method to set the global exception handler. If custom NSSetUncaughtExceptionHandler to monitor events, leads to a third party (such as Bugly) failure monitoring, has integrated junior partner needs to pay attention to the third party monitoring platform.

Register handler for global exception handling. Register handler for program startup or other entry:


② When the online program crashes, the code will be executed in the previously registered Handle and the error information will be saved locally.


③ Find the problem through the dSYM symbol table of the saved online APP.

The symbol table generated when iOS is built. It is a mapping table of memory addresses and function names, file names, and line numbers. The symbol table elements look like this:

When crash is applied, we can use the stack information during crash to get the stack information corresponding to the source code and see how many lines of the code are in error, so we can quickly locate the error code and solve the problem quickly.

After obtaining the dSYM symbol table and the error log of the previous program crash, we can locate the problem.


4. Use the ATOS command to locate the fault.

Atos command to symbolize a particular module loading address atos [-arch architecture name] [-o symbol table] [-l module address] [method address]

With terminal computing, the hexadecimal address range is first obtained.

Terminal code execution:

In this way, the problem code can be located.



Part 2: Mach exceptions and signal crashes

➸ 2.1 Mach and Signal

Mach is the microkernel core of Mac OS and iOS operating system. Mach exception refers to the lowest kernel-level exception. Therefore, when an exception occurs in APP, Mach is the first one to detect the exception.

Mach, which catches the exception first, then converts all exceptions into the appropriate Unix signal and posts it to the error thread. You can then register the signal type you want to listen on to capture the signal. Objective-c exception handling is not used to obtain signal. If you want to process signal, you need to register SIGABRT, SIGBUS, SIGSEGV and other handlers when signal occurs using the SIGNAL mechanism of Unix standard. From this function we can output stack information, version information, and anything else we want. MySignalHandler (SIGSEGV, mySignalHandler) signal (SIGSEGV, mySignalHandler)



➸ 2.2 Signal Description

Terminate (Terminate process), Ignore(Terminate process), Dump(Terminate process and Dump core) : To end a process and generate core dump, which prints the memory information of the process), Stop (to suspend a process, mostly used for debugging), and Cont (to resume a previously suspended process, mostly used for debugging).

Signal Signal type:

The signal name

The default processing

instructions

SIGABRT

Dump

Program termination command

SIGALRM

Terminate

Program timeout signal

SIGILL

Dump

Program invalid instruction signal

SIGHUP

Terminate

Program terminal abort signal

SIGINT

Terminate

Program keyboard interrupt signal

SIGKILL

Terminate

Program force end signal

SIGTERM

Terminate

Program termination signal

SIGSTOP

Stop

Program keyboard abort signal

SIGSEGV

Dump

Program invalid memory abort signal

SIGBUS

Dump

Program memory bytes not aligned abort signal

SIGPIPE

Terminate

The program Socket sent an abort signal

If no corresponding handler is set for a signal, the default handler is used, otherwise the signal is intercepted by the process and the corresponding handler is called. In the absence of a handler, a program can specify two behaviors: ignore the signal SIG_IGN or use the default handler SIG_DFL. But there are two signals that cannot be intercepted and processed: SIGKILL and SIGSTOP.


➸ 2.3 Processing signal

① Register the handler that handles the global exception signal. Register it at program startup or other entry.

SignalExceptionHandler is a callback to signal error. When a signal fails, you can call back to this method.


② Do not test SignalHandler in the DEBUG environment. Because system debug will intercept first. After running it once on the simulator, I closed the debug state, and then directly clicked the app we built on the simulator to run it. Get the following log:


Part 3: Summary

For application crash, there are a lot of excellent third-party platform (such as Allies, bugly) provides logging and dot function, have been able to meet the development need daily, but learning the crash of the commonly used was able to help us understand the iOS operating mechanism, these are often seen in the development of some of the crash, in the actual processing may be complicated, You need to use multiple methods at the same time to locate problems and use them flexibly.


About the author:

Zhang Li, Development engineer of User Experience Technology Department, Minsheng Technology Co., LTD.