g_spawn_*() is not thread-safe on Windows when an environment table is provided
See Python issue 6476. This applies to GLib as well, which i've discovered while trying to call g_spawn_sync()
from multiple threads at the same time, while providing an environment table for each call (my initial hypothesis was that the same environment table being shared by multiple threads is the problem, but even after i gave each thread a copy of the envtable, it still crashed).
The gist is that _wspawn*e()
calls (like this one) are not thread-safe (MSVCRT uses some kind of static variable internally, somewhere).
Since the use of _wspawn*e()
is not going to stop anytime soon (the best prognosis is that at some point we'll be able to use CreateProcess()
more, but spawn-based code will have to remain in use for compatibility in some cases — see #2214), and since MS is probably not going to fix this, i propose:
- Document this. People should know that
_*spawn*e()
is not thread-safe, and thatg_spawn_*()
might call it internally. - Implement a thin wrapper versions of
_*spawn*e()
(let's give them descriptive names, like_wspawnve_thread_safe()
) that call the appropriate MSVCRT functions while holding a mutex (normal static mutex), then use these wrappers everywhere in GLib. This will solve the problem for GLib as a whole, but documentation should still warn people that mixingg_spawn_*()
and_*spawn*e()
is dangerous, since GLib can't do anything to serialize the calls made by the user code.
I have no idea how far this spreads (is normal, non-env version of spawn()
also affected?). Once i get my PC up and running, i'll try to reproduce this in a small testcase.
Right now i can only say that a workaround (holding a mutex while calling g_spawn_sync()
) fixed the crashes in my app.