Skip to content

Double DECREF from deque.extend() if block allocation fails in deque_append_lock_held #152951

Description

@stestagg

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

deque_extend_impl(dequeobject *deque, PyObject *iterable)

Calls deque_append_lock_held for each item:
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:

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    extension-modulesC modules in the Modules dirtype-crashA hard crash of the interpreter, possibly with a core dump

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions