g_spawn_* functions break POSIX requirements and deadlock the child process under certain conditions
Submitted by Aleksander Wabik
Link to original bug (#738620)
Description
g_spawn_* functions call internally fork_exec_with_pipes(), which calls do_exec().
In these functions, there are called functions which are not async-signal-safe, like readdir, dirfd, and probably others (I apology for not providing a complete callstack, but I reproduced a bug once and without full debug info).
The final result is that after the fork, the child process ends up in the allocator to allocate or free some memory. If the allocator (like uClibc's malloc, or older versions of tcmalloc) does not register pthread_atfork handlers to ensure clean internal state during fork, the child process may deadlock on an internal allocator's mutex which was held by a different thread in the parent process during the fork().
This bug reproduces for example when I call gst_init() during the application's normal work, while other threads are already working. GStreamer forks to exec the gst-plugin-scanner, but due to bugs in g_spawn_async_with_pipes() it deadlocks.
I know that this bug could be fixed in the allocator, and major allocators (glib's ptmalloc, firefoxes jemalloc) do register atfork handlers, but by the POSIX spec after the fork only the async-signal-safe functions should be called in the child before it performs exec, so strictly speaking, the real bug is in glib.