https://github.com/python/cpython/commit/79088e0d82931c21fa72eadc416a18b7b0fdf9c1
commit: 79088e0d82931c21fa72eadc416a18b7b0fdf9c1
branch: main
author: larryhastings <[email protected]>
committer: encukou <[email protected]>
date: 2026-05-20T00:27:04+02:00
summary:
gh-150042: queue.SimpleQueue.put: fix minor refleak. (GH-150043)
If queue.SimpleQueue.put can't handoff the item to a
waiting thread, and fails to allocate memory when adding
the item to a ringbuf, it would leak a reference. Fixed.
files:
A
Misc/NEWS.d/next/Core_and_Builtins/2026-05-18-16-54-54.gh-issue-150042.LSr5W8.rst
M Modules/_queuemodule.c
diff --git
a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-18-16-54-54.gh-issue-150042.LSr5W8.rst
b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-18-16-54-54.gh-issue-150042.LSr5W8.rst
new file mode 100644
index 00000000000000..18a4fbd9dadd60
--- /dev/null
+++
b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-18-16-54-54.gh-issue-150042.LSr5W8.rst
@@ -0,0 +1 @@
+Fix refleak in queue.SimpleQueue.put if memory allocation fails.
diff --git a/Modules/_queuemodule.c b/Modules/_queuemodule.c
index ed925f3525a9a7..d5ba36273c8262 100644
--- a/Modules/_queuemodule.c
+++ b/Modules/_queuemodule.c
@@ -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)
{
@@ -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;
@@ -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]
@@ -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;
}
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]