Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ensure Objective-C Code Execution Before Cocoa Application Exits

Assume that a cocoa app must execute some vitally important objective-c operation before it exits (for any reason—crash or quit).

Is it possible to ensure the execution of arbitrary objective-c code in response to every crash event? (SIGINT, SIGBUS, SIGSEGV, etc, ignoring the "uncatchables" (SIGSTOP, SIGKILL, bolt of lightning, etc.))


It would be helpful to know what your hooks are trying to do.

For example: let's say that for the app to operate, it absolutely must change the value of some mutable system-wide configuration variable X. On launch, the app takes a snapshot of X's current state and then modifies it. When the app exits successfully, it just restores X to the stashed, original value before terminating. My question is this: is it possible to ensure that X gets restored even if the app crashes?

like image 772
pje Avatar asked Sep 30 '12 18:09

pje


1 Answers

No, there is no way to guarantee that any given piece of code will be executed at application termination exactly because the user might terminate the application in a fashion that cannot be caught by the application (like, for example, pulling the plug on a desktop machine).

Your code absolutely must be hardened against unexpected termination.

How much you need to harden it depends on your app. In document based apps (prior to the modern auto-saving-frequently model), losing data after last save was expected (and annoying).

For your app, you need to balance the cost of persistency with the value of the data persisted.


I'm only interested in the termination signals that can be caught.

There is a difference between "can be caught" and "can do anything useful". Lots of signals can be caught, as you've noted.

However, you really can't do anything in a signal handler. Technically, you can't even allocate memory.

As well, a signal or exception is generally generated because the application has entered into an undefined, catastrophically corrupted, state. Thus, you can't count on any internal state within the application being usable.

I've seen numerous cases where an app will attempt to save off user state when a crash occurs, only to quite merrily write corrupted state that ends up causing the user to lose significantly more data.

It would be helpful to know what your hooks are trying to do.


See the sigaction man page for more information.

Specifically, the list of functions that are safe to call includes _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(), and strlcat().

All functions not in the above lists are considered to be unsafe with respect to signals. That is to say, the behaviour of such functions when called from a signal handler is undefined. In general though, signal handlers should do little more than set a flag; most other actions are not safe.

Translation: You really can't do much of anything useful in a signal handler.

Mpte a;sp tjat sogma; ,au ne de;overed pm amu tjread amd ,ogjt ne de;overed nu interrupting a currently executing function.

What I meant to type: keep in mind that signal handlers may be delivered on a random thread and might interrupt a currently executing function, too. I.e. the state of your app is likely somewhat indeterminate.

like image 185
bbum Avatar answered Sep 29 '22 21:09

bbum