[Python-Dev] Reference leak in thread._local (original) (raw)
Ben.Cottrell at nominum.com Ben.Cottrell at nominum.com
Thu Aug 28 00:28:50 CEST 2008
- Previous message: [Python-Dev] confusing exec error message in 3.0
- Next message: [Python-Dev] Reference leak in thread._local
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
I noticed that thread._local can leak references if objects are being stored inside the thread._local object whose destructors might release the GIL.
The way this happens is that in Modules/threadmodule.c, in the _ldict() function, it does things like this:
Py_CLEAR(self->dict);
Py_INCREF(ldict);
self->dict = ldict;
If the Py_CLEAR ends up taking away the last reference to an object contained in the dict, and a thread context switch occurs during that object's deallocation, then self->dict might not be NULL on return from Py_CLEAR; another thread might have run, accessed something in the same thread._local object, and caused self->dict to be set to something else (and Py_INCREF'ed). So when we blindly do the assignment into self->dict, we may be overwriting a valid reference, and not properly Py_DECREFing it.
The recent change (revision 64601 to threadmodule.c) did not address context switches during the Py_CLEAR call; only context switches during tp_init.
The attached patch (against trunk) is my first attempt at fixing this. It detects if self->dict has been set to something else after the Py_CLEAR, and retries the Py_CLEAR (because _ldict really only cares about installing the proper value of self->dict for the currently running thread).
However, I am still uncomfortable about the fact that local_getattro and local_setattro discard the value returned from _ldict, and instead hand off control to the PyObject_Generic layer and trust that by the time self->dict is actually used, it still has the correct value for the current thread. Would it be better to, say, inline a copy of the PyObject_Generic* functions inside local_getattro/local_setattro, and force the operations to be done on the actual dict returned by _ldict()?
Thanks,
~Ben
-------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: text/x-patch Size: 672 bytes Desc: not available URL: <http://mail.python.org/pipermail/python-dev/attachments/20080827/6e8ed9f7/attachment.bin>
- Previous message: [Python-Dev] confusing exec error message in 3.0
- Next message: [Python-Dev] Reference leak in thread._local
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]