Attack of the zombie processes

I have an application that consists of a background process which launches another tool at certain times to do some work. I was doing this the standard Unix way:

if ((pid = fork()) == 0) {
    exec("/some/application");
} else {
    wait(&status);
}

I’ve been attempting to convert it to a single binary rather than two separate files. I figured I could simply have it run the code to do the timed task inline after I fork() instead of launching a separate binary.

I found that the forked process was crashing immediately when it attempted to use a CFRunLoop function. Even more annoying, the child process can’t be debugged in gdb as far as I can tell. It ended up crashing, and getting respawned so quickly it filled up the process table with zombie processes so I could no longer run anything else.

$ ps ax
-bash: fork: Resource temporarily unavailable

It turns out you can’t continue after a fork() without execing.

The problem is that fork() does not actually replicate all kernel resources (and perhaps other bits I don’t know about) from the parent process into the child, but it does replicate memory. Thus there can be code which thinks everything is happy because the memory holding handles to kernel esources looks like it is initialized and whatnot, but the kernel resources are missing underneath.

Basically, after fork() you need to execve() (or other exec variant), so that library initializers and whatnot are executed in the context of the child to do any 1-time set-up or whatever else the libraries normally do when an app is launched.

Thanks to Chris Hanson for pointing this out.