[Python-Dev] Possible GIL/threading issue involving subprocess and PyMem_MALLOC...
Gregory P. Smith
greg at krypto.org
Fri Dec 21 02:47:40 CET 2012
On Thu, Dec 20, 2012 at 10:43 AM, Trent Nelson <trent at snakebite.org> wrote:
> This seems odd to me so I wanted to see what others think. The unit
> test Lib/unittest/test/test_runner.py:Test_TextRunner.test_warnings
> will eventually hit subprocess.Popen._communicate.
>
> The `mswindows` implementation of this method relies on threads to
> buffer stdin/stdout. That'll eventually result in PyOs_StdioReadline
> being called without the GIL being held. PyOs_StdioReadline calls
> PyMem_MALLOC, PyMem_FREE and possibly PyMem_REALLOC.
>
Those threads are implemented in Python so how would the GIL ever not be
held?
-gps
>
> On a debug build, these macros are redirected to their _PyMem_Debug*
> counterparts. The call hierarchy for _PyMem_DebugMalloc looks like
> this:
>
> void *
> _PyMem_DebugMalloc(size_t nbytes)
> {
> return _PyObject_DebugMallocApi(_PYMALLOC_MEM_ID, nbytes);
> }
>
> /* generic debug memory api, with an "id" to
> identify the API in use */
> void *
> _PyObject_DebugMallocApi(char id, size_t nbytes)
> {
> uchar *p; /* base address of malloc'ed block */
> uchar *tail; /* p + 2*SST + nbytes ==
> pointer to tail pad bytes */
> size_t total; /* nbytes + 4*SST */
>
> bumpserialno();
> ------------^^^^^^^^^^^^^^^
>
> total = nbytes + 4*SST;
> if (total < nbytes)
> /* overflow: can't represent total as a size_t */
> return NULL;
>
> p = (uchar *)PyObject_Malloc(total);
> -------------------------^^^^^^^^^^^^^^^^^^^^^^^
> if (p == NULL)
> return NULL;
>
> <snip>
>
> Both bumpserialno() and PyObject_Malloc affect global state. The
> latter
> also has a bunch of LOCK() and UNLOCK() statements, but these end up
> being
> no-ops:
>
> /*
> * Python's threads are serialized,
> * so object malloc locking is disabled.
> */
> #define SIMPLELOCK_DECL(lock) /* simple lock declaration */
> #define SIMPLELOCK_INIT(lock) /* allocate (if needed) and ... */
> #define SIMPLELOCK_FINI(lock) /* free/destroy an existing */
> #define SIMPLELOCK_LOCK(lock) /* acquire released lock */
> #define SIMPLELOCK_UNLOCK(lock) /* release acquired lock */
> ...
> /*
> * This malloc lock
> */
> SIMPLELOCK_DECL(_malloc_lock)
> #define LOCK() SIMPLELOCK_LOCK(_malloc_lock)
> #define UNLOCK() SIMPLELOCK_UNLOCK(_malloc_lock)
> #define LOCK_INIT() SIMPLELOCK_INIT(_malloc_lock)
> #define LOCK_FINI() SIMPLELOCK_FINI(_malloc_lock)
>
> The PyObject_Malloc() one concerns me the most, as it affects huge
> amounts of global state. Also, I just noticed PyOs_StdioReadline()
> can call PyErr_SetString, which will result in a bunch of other
> calls that should only be made whilst the GIL is held.
>
> So, like I said, this seems like a bit of a head scratcher. Legit
> issue or am I missing something?
>
> Trent.
> _______________________________________________
> Python-Dev mailing list
> Python-Dev at python.org
> http://mail.python.org/mailman/listinfo/python-dev
> Unsubscribe:
> http://mail.python.org/mailman/options/python-dev/greg%40krypto.org
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-dev/attachments/20121220/274d0869/attachment.html>
More information about the Python-Dev
mailing list