Skip to content

Commit 3714ac6

Browse files
committed
gh-150042: queue.SimpleQueue.put: fix minor refleak.
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.
1 parent 6d5be4b commit 3714ac6

2 files changed

Lines changed: 17 additions & 21 deletions

File tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix refleak in queue.SimpleQueue.put if memory allocation fails.

Modules/_queuemodule.c

Lines changed: 16 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -154,8 +154,6 @@ RingBuf_Get(RingBuf *buf)
154154
}
155155

156156
// Returns 0 on success or -1 if the buffer failed to grow.
157-
//
158-
// Steals a reference to item.
159157
static int
160158
RingBuf_Put(RingBuf *buf, PyObject *item)
161159
{
@@ -165,11 +163,10 @@ RingBuf_Put(RingBuf *buf, PyObject *item)
165163
// Buffer is full, grow it.
166164
if (resize_ringbuf(buf, buf->items_cap * 2) < 0) {
167165
PyErr_NoMemory();
168-
Py_DECREF(item);
169166
return -1;
170167
}
171168
}
172-
buf->items[buf->put_idx] = item;
169+
buf->items[buf->put_idx] = Py_NewRef(item);
173170
buf->put_idx = (buf->put_idx + 1) % buf->items_cap;
174171
buf->num_items++;
175172
return 0;
@@ -276,16 +273,13 @@ maybe_handoff_item(void *arg, void *park_arg, int has_more_waiters)
276273
{
277274
HandoffData *data = (HandoffData*)arg;
278275
PyObject **item = (PyObject**)park_arg;
279-
if (item == NULL) {
280-
// No threads were waiting
281-
data->handed_off = false;
282-
}
283-
else {
276+
data->queue->has_threads_waiting = has_more_waiters;
277+
278+
data->handed_off = item != NULL;
279+
if (data->handed_off) {
284280
// There was at least one waiting thread, hand off the item
285-
*item = data->item;
286-
data->handed_off = true;
281+
*item = Py_NewRef(data->item);
287282
}
288-
data->queue->has_threads_waiting = has_more_waiters;
289283
}
290284

291285
/*[clinic input]
@@ -307,21 +301,22 @@ _queue_SimpleQueue_put_impl(simplequeueobject *self, PyObject *item,
307301
int block, PyObject *timeout)
308302
/*[clinic end generated code: output=4333136e88f90d8b input=a16dbb33363c0fa8]*/
309303
{
310-
HandoffData data = {
311-
.handed_off = 0,
312-
.item = Py_NewRef(item),
313-
.queue = self,
314-
};
315304
if (self->has_threads_waiting) {
305+
HandoffData data = {
306+
.handed_off = 0,
307+
.item = item,
308+
.queue = self,
309+
};
316310
// Try to hand the item off directly if there are threads waiting
317311
_PyParkingLot_Unpark(&self->has_threads_waiting,
318312
maybe_handoff_item, &data);
319-
}
320-
if (!data.handed_off) {
321-
if (RingBuf_Put(&self->buf, item) < 0) {
322-
return NULL;
313+
if (data.handed_off) {
314+
Py_RETURN_NONE;
323315
}
324316
}
317+
if (RingBuf_Put(&self->buf, item) < 0) {
318+
return NULL;
319+
}
325320
Py_RETURN_NONE;
326321
}
327322

0 commit comments

Comments
 (0)