Repository navigation
Double DECREF from deque.extend() if block allocation fails in deque_append_lock_held #152951
Description
Crash report
What happened?
The following double-frees integers being added to the deque:
from collections import deque
import _testcapi
for n in range(100):
try:
_testcapi.set_nomemory(n, n+1)
deque().extend(range(1000, 1500))
except Exception as e:
pass
finally:
_testcapi.remove_mem_hooks() ./Include/refcount.h:520: _Py_NegativeRefcount: Assertion failed: object has negative ref count
<object at 0x105f21580 is freed>
Problem
deque_extend_impl
cpython/Modules/_collectionsmodule.c
Line 479 in ac1acb6
| deque_extend_impl(dequeobject *deque, PyObject *iterable) |
Calls
deque_append_lock_held for each item:cpython/Modules/_collectionsmodule.c
Lines 514 to 518 in ac1acb6
| if (deque_append_lock_held(deque, item, maxlen) == -1) { | |
| Py_DECREF(item); | |
| Py_DECREF(it); | |
| return NULL; | |
| } |
And if the call fails, frees the references.
BUT, the only time deque_append_lock_held returns -1 is if a new block allocation fails:
cpython/Modules/_collectionsmodule.c
Lines 344 to 348 in ac1acb6
| block *b = newblock(deque); | |
| if (b == NULL) { | |
| Py_DECREF(item); | |
| return -1; | |
| } |
And in this case,
item has been decref'd already.
As far as I can tell, deque_append_lock_held reliably steals the reference from callers, so deque_extend_impl should not attempt to decref item after calling deque_append_lock_held in any situation.
CPython versions tested on:
CPython main branch
Operating systems tested on:
macOS
Output from running 'python -VV' on the command line:
Python 3.16.0a0 (heads/main-dirty:c4739533f33, Jul 3 2026, 12:23:57) [Clang 21.0.0 (clang-2100.3.20.102)]
Linked PRs
- gh-152951 - Fix double DECREF when
newblockfails during deque.extend calls #152961 - [3.15] gh-152951 - Fix double DECREF when
newblockfails during deque.extend calls (GH-152961) #152971 - [3.14] gh-152951 - Fix double DECREF when
newblockfails during deque.extend calls (GH-152961) #152972 - [3.13] gh-152951 - Fix double DECREF when
newblockfails during deque.extend calls (GH-152961) #152973
Activity
[-]Double free from deque.extend() if block allocation fails in `deque_append_lock_held`[/-][+]Double DECREF from deque.extend() if block allocation fails in `deque_append_lock_held`[/+]gh-152951 - Fix double DECREF when `newblock` fails during deque.exte…
[3.13] gh-152951 - Fix double DECREF when `newblock` fails during deq…
[3.14] gh-152951 - Fix double DECREF when `newblock` fails during deq…
[3.15] gh-152951 - Fix double DECREF when `newblock` fails during deq…