Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix refleak in queue.SimpleQueue.put if memory allocation fails.
37 changes: 16 additions & 21 deletions Modules/_queuemodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -154,8 +154,6 @@ RingBuf_Get(RingBuf *buf)
}

// Returns 0 on success or -1 if the buffer failed to grow.
//
// Steals a reference to item.
static int
RingBuf_Put(RingBuf *buf, PyObject *item)
{
Expand All @@ -165,11 +163,10 @@ RingBuf_Put(RingBuf *buf, PyObject *item)
// Buffer is full, grow it.
if (resize_ringbuf(buf, buf->items_cap * 2) < 0) {
PyErr_NoMemory();
Py_DECREF(item);
return -1;
}
}
buf->items[buf->put_idx] = item;
buf->items[buf->put_idx] = Py_NewRef(item);
buf->put_idx = (buf->put_idx + 1) % buf->items_cap;
buf->num_items++;
return 0;
Expand Down Expand Up @@ -276,16 +273,13 @@ maybe_handoff_item(void *arg, void *park_arg, int has_more_waiters)
{
HandoffData *data = (HandoffData*)arg;
PyObject **item = (PyObject**)park_arg;
if (item == NULL) {
// No threads were waiting
data->handed_off = false;
}
else {
data->queue->has_threads_waiting = has_more_waiters;

data->handed_off = item != NULL;
if (data->handed_off) {
// There was at least one waiting thread, hand off the item
*item = data->item;
data->handed_off = true;
*item = Py_NewRef(data->item);
}
data->queue->has_threads_waiting = has_more_waiters;
}

/*[clinic input]
Expand All @@ -307,21 +301,22 @@ _queue_SimpleQueue_put_impl(simplequeueobject *self, PyObject *item,
int block, PyObject *timeout)
/*[clinic end generated code: output=4333136e88f90d8b input=a16dbb33363c0fa8]*/
{
HandoffData data = {
.handed_off = 0,
.item = Py_NewRef(item),
.queue = self,
};
if (self->has_threads_waiting) {
HandoffData data = {
.handed_off = 0,
.item = item,
.queue = self,
};
// Try to hand the item off directly if there are threads waiting
_PyParkingLot_Unpark(&self->has_threads_waiting,
maybe_handoff_item, &data);
}
if (!data.handed_off) {
if (RingBuf_Put(&self->buf, item) < 0) {
return NULL;
if (data.handed_off) {
Py_RETURN_NONE;
}
}
if (RingBuf_Put(&self->buf, item) < 0) {
return NULL;
}
Py_RETURN_NONE;
}

Expand Down
Loading