Author neologix
Recipients christian.heimes, neologix
Date 2013-01-11.08:36:42
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1357893404.57.0.0716117445862.issue16929@psf.upfronthosting.co.za>
In-reply-to
Content
After optimizing epoll() to use a per-instance buffer like poll() does (http://bugs.python.org/issue16876), I realized that it wasn't thread-safe, and can result in crashes:
"""
 ./python /tmp/test.py
*** glibc detected *** ./python: free(): corrupted unsorted chunks: 0x0000000001c8e690 ***
======= Backtrace: =========
/lib64/libc.so.6[0x3041c75676]
./python[0x4fd9ae]
./python(PyThreadState_DeleteCurrent+0x10c)[0x4fdb91]
./python[0x52a444]
/lib64/libpthread.so.0[0x30428077e1]
/lib64/libc.so.6(clone+0x6d)[0x3041ce153d]
======= Memory map: ========
[...]
"""

The problem is that poll (and now epoll) array is stored per-instance, and if second call to poll() is made while another thread is currently blocked on poll(), the array is reallocated (through PyMem_Resize()) if the buffer size has changed (if the number of FDs registered has changed).

"""
static int
update_ufd_array(pollObject *self)
[...]
    self->ufd_len = PyDict_Size(self->dict);
    PyMem_RESIZE(self->ufds, struct pollfd, self->ufd_len);
[...]
"""

can be called while another thread is blocked there:
"""
    /* call poll() */
    Py_BEGIN_ALLOW_THREADS
    poll_result = poll(self->ufds, self->ufd_len, timeout);
    Py_END_ALLOW_THREADS
"""

So when the first call to poll() returns, it can end up in SIGSEGV or heap corruption (unless the array was increased an realloc() was able to expand it in-place).

Reproducer script attached.
History
Date User Action Args
2013-01-11 08:36:44neologixsetrecipients: + neologix, christian.heimes
2013-01-11 08:36:44neologixsetmessageid: <1357893404.57.0.0716117445862.issue16929@psf.upfronthosting.co.za>
2013-01-11 08:36:44neologixlinkissue16929 messages
2013-01-11 08:36:42neologixcreate