g_spawn family does not appear to be safe in multi-threaded programs
Submitted by Chris Vine
The g_spawn* family of functions does not appear to be safe in multi-threaded programs, particularly on linux. Given that gio is now multi-threaded, this means that most uses of g_spawn*, including in GSubprocess, will not be safe.
This arises because by default the g_spawn* functions (via do_exec() in glib/gspawn.c) walk an open descriptor list setting the FD_CLOEXEC flag on all file descriptors (except the descriptors for stdin, stdout and stderr) after one or more forks and before the eventual exec. It does this either using the system supplied fdwalk (for solaris and BSDs) or by using an internal glib-supplied fdwalk function for linux and other posix-like OSes (also in glib/spawn.c).
The internal glib-supplied fdwalk for linux examines /proc/self/fd and to do so calls opendir, closedir and readdir. opendir and closedir are definitely not async-signal-safe and therefore not safe to be called between a fork and an exec, and in my version of glibc (2.21) call malloc and free respectively and therefore have potential for deadlock. A fallback version of fdwalk for other posix-like OSes calls getrlimit (almost certainly informally safe) and sysconf (which prior to POSIX.1-2008 was required to be async-signal-safe, and although that is no longer the case it is almost certainly informally safe). The last two points are anyway not killers because they could equally well be called before the fork.
In solaris and the BSDs, the system-supplied fdwalk() is not guaranteed to be async-signal-safe and is therefore not guaranteed to be safe between a fork and an exec in a multi-threaded program. I have no idea if it is informally safe - it would not be if it makes use of opendir/closedir.