Author neologix
Recipients christian.heimes, neologix
Date 2013-01-11.08:36:42
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <>
After optimizing epoll() to use a per-instance buffer like poll() does (, I realized that it wasn't thread-safe, and can result in crashes:
 ./python /tmp/
*** glibc detected *** ./python: free(): corrupted unsorted chunks: 0x0000000001c8e690 ***
======= Backtrace: =========
======= 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() */
    poll_result = poll(self->ufds, self->ufd_len, timeout);

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.
Date User Action Args
2013-01-11 08:36:44neologixsetrecipients: + neologix, christian.heimes
2013-01-11 08:36:44neologixsetmessageid: <>
2013-01-11 08:36:44neologixlinkissue16929 messages
2013-01-11 08:36:42neologixcreate