Skip to content

weakrefobject.c: WRAP_BINARY ref leak with dead proxy #148263

@prakashsellathurai

Description

@prakashsellathurai

Bug report

Bug description:

Bug report

Bug description:

Parent: #146102

https://gist.github.com/devdanzin/f7d0c7694b2be2345f4cf85f4eedc3ee

Summary

When first UNWRAP(x) succeeds but second UNWRAP(y) fails (dead proxy), x's new reference is leaked. Affects ~20 binary operators (+, -, *, /, |, &, ^, etc.).

Reproducer

import weakref, sys, gc

class C:
    def __add__(self, other): return NotImplemented
    def __radd__(self, other): return NotImplemented

obj = type('D', (), {})()
dead = weakref.proxy(obj)
del obj; gc.collect()

live_obj = C()
live = weakref.proxy(live_obj)

before = sys.gettotalrefcount()
for i in range(10000):
    try:
        live + dead
    except ReferenceError:
        pass
after = sys.gettotalrefcount()
print(f"Leaked {after - before} refs (~{(after-before)//10000}/call)")

which gives

(venv) PS C:\Users\Prakash\Documents\work\projects\cpython>
>> .\python.bat  .\tmp\test.py
Running Debug|x64 interpreter...
Leaked 10003 refs (~1/call)

CPython versions tested on:

CPython main branch

Operating systems tested on:

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    interpreter-core(Objects, Python, Grammar, and Parser dirs)type-bugAn unexpected behavior, bug, or error

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions