[TIMOB-11217] iOS: Signals are not being handled by the TiExceptionHandler
GitHub Issue | n/a |
---|---|
Type | Bug |
Priority | High |
Status | Closed |
Resolution | Hold |
Resolution Date | 2012-10-16T02:38:13.000+0000 |
Affected Version/s | Release 3.0.0 |
Fix Version/s | n/a |
Components | iOS |
Labels | core |
Reporter | Jeff Haynie |
Assignee | Max Stepanov |
Created | 2012-09-30T05:53:36.000+0000 |
Updated | 2017-03-21T21:13:28.000+0000 |
Description
it looks like not all types of errors are handled in TiExceptionHandler
if you add the following:
abort()
in a module method, the app will crash.
see http://cocoawithlove.com/2010/05/handling-unhandled-exceptions-and.html for a good example on how to handle signals as well as normal cocoa exceptions (in addition to script error and NSExceptionHandler). the signal handling code must be added to TiExceptionHandler.m
submitted pull request at https://github.com/appcelerator/titanium_mobile/pull/3086
Going to quote Mike Ash from Friday Q&A 2011-04-01: Signal Handling: {quote} The problem is that signals are delivered asynchronously, and the function registered here is also invoked asynchronously. Code always has to run on a thread somewhere. Depending on how the signal is generated, the handler is either run on the thread that the signal is associated with (for example, a SIGSEGV handler will run on the thread that segfaulted) or it will run on an arbitrary thread in the process. The problem is that it's essentially an interrupt in userland, and whatever code was running when it came in will be paused until the handler is done. As anyone who was around in the classic Mac days knows, writing code that runs in an interrupt is hard. The problem is reentrancy. Many people confuse reentrancy with thread safety, but they are not the same concept, although they are somewhat similar. Thread safety means that a particular piece of code can run on multiple threads at the same time safely. Thread safety is most commonly accomplished by using locks. A call acquires a lock, does work, releases the lock. A second thread that comes along in the middle will block until the first thread is done. If code is reentrant that means that a particular piece of code can run multiple times on the same thread safely. This is different and considerably harder. What if you take the thread safety approach of locking and apply it to reentrancy? The first call acquires the lock. While it's active, the code is called again. It tries to acquire the lock, but the lock is already taken, so it blocks. However, the first call can't run until the second call is done. The second call can't run until the first call is done. The result is a frozen program. Writing reentrant code is hard, and as a result very few system functions are reentrant. Because a signal handler functions as an interrupt, it can only call reentrant code. You can't call something as simple as printf safely, because printf could take a lock, and if there's already an active call to printf on the thread where the handler runs, you'll deadlock. The sigaction man page gives a list of functions you are allowed to call from a signal handler. It's pretty limited. The complete list is: _exit(), access(), alarm(), cfgetispeed(), cfgetospeed(), cfsetispeed(), cfsetospeed(), chdir(), chmod(), chown(), close(), creat(), dup(), dup2(), execle(), execve(), fcntl(), fork(), fpathconf(), fstat(), fsync(), getegid(), geteuid(), getgid(), getgroups(), getpgrp(), getpid(), getppid(), getuid(), kill(), link(), lseek(), mkdir(), mkfifo(), open(), pathconf(), pause(), pipe(), raise(), read(), rename(), rmdir(), setgid(), setpgid(), setsid(), setuid(), sigaction(), sigaddset(), sigdelset(), sigemptyset(), sigfillset(), sigismember(), signal(), sigpending(), sigprocmask(), sigsuspend(), sleep(), stat(), sysconf(), tcdrain(), tcflow(), tcflush(), tcgetattr(), tcgetpgrp(), tcsendbreak(), tcsetattr(), tcsetpgrp(), time(), times(), umask(), uname(), unlink(), utime(), wait(), waitpid(), write(), aio_error(), sigpause(), aio_return(), aio_suspend(), sem_post(), sigset(), strcpy(), strcat(), strncpy(), strncat(), strlcpy(), strlcat(). Finally, the list ends with this amusing note: "...and perhaps some others." "Perhaps" is not a nice word to run into in this sort of documentation. *You can call your own reentrant code, but you probably don't have any, because it's hard to write, it can't call any system functions except from the above list, and you never had any reason to write it before. For the Objective-C types, note that objc_msgSend is not reentrant, so you cannot use any Objective-C from a signal handler.* {color:red}*There is very little that you can do safely. There is so little that I'm not even going to discuss how to get anything done, because it's so impractical to do so, and instead will simply tell you to avoid using signal handlers unless you really know what you're doing and you enjoy pain.* {color} {quote} As well, from the source mentioned in the description: {quote} *Limitations* *The signal handler is not re-entrant* Remember from the paragraph at the beginning: The code in this post performs signal handling in non re-entrant way — this is not a reliable thing to do and is only done because proper re-entrant coding is brutally difficult and the assumption is that your program has already fatally crashed so we're not too worried. If multiple signals are caught, this code probably won't help at all. If you want to learn how to write signal handlers for non-crash related signals or learn how to write proper re-entrant signal handling, I'm afraid you'll need to look elsewhere — there's not enough space here for me to show you and it's really hard. Ignoring this constraint here is okay for debug code only where we assume we're only going to get 1 signal. {quote} The best what we could do is to integrate PLCrashReporter framework to generate crash report during signal handler, but no details could be displayed to users. The crash log could be potentially sent to a server on next app launch. This will effectively match what iOS does by default with crashing apps.
Closing ticket due to the time that has passed since this was filed.