Web lists-archives.com

g_spawn_async_with_pipes is not thread safe


    I've discovered a subtle, but quite a serious issue with g_spawn_async_with_pipes API. The problem is that under some circumstances this API causes memory allocation operations to be called from the forked child process, which is illegal in multi-threaded environment an may lead to undefined behaviour (I've seen segfaults and infinite loops in malloc in the child). It happens at least in the following situations:

1. If SPAWN_LEAVE_DESCRIPTORS_OPEN flag is _not_ given, which is often default option, then child (at least on Linux) does the following call chain fork_exec_with_pipes->do_exec->fdwalk which uses opendir which in turn uses memory allocation for DIR structure. Some API, like g_spawn_command_line_sync, doesn't allow to specify flags at all.

2. If script or relative path command is given to execute in a child, then g_execute also uses g_malloc as seen from the source code. This can't be avoided by flags at all.

3. If child_setup is given by user which also may do some memory operations.

This risky behaviour is not described in the docs and what makes the situation even worse is that although the application from user point of view may be single-threaded, the usage of, for example, DBus API implicitly creates an additional dbus thread which does memory allocations, so the application effectively becomes multi-threaded under the hood.

As I understand, this is hard (maybe even impossible) to fix in a generic way, but at least docs should explicitly say that this API is not thread safe if SPAWN_LEAVE_DESCRIPTORS_OPEN is not given or script/relative command is given to be executed or schild_setup uses some mallocs.

I have worked around this bug in my code by using g_spawn_sync with absolute path to a command and setting also SPAWN_LEAVE_DESCRIPTORS_OPEN flag. My code is glibmm based, but it shouldn't matter at all, because glibmm is a very thin wrapper around glib APIs in this case.

BR, Andrey

gtk-devel-list mailing list