Skip to content

gh-148263: Fix refcount leak in weakref proxy operations#148486

Open
prakashsellathurai wants to merge 11 commits intopython:mainfrom
prakashsellathurai:hotfix/148263
Open

gh-148263: Fix refcount leak in weakref proxy operations#148486
prakashsellathurai wants to merge 11 commits intopython:mainfrom
prakashsellathurai:hotfix/148263

Conversation

@prakashsellathurai
Copy link
Copy Markdown

@prakashsellathurai prakashsellathurai commented Apr 13, 2026

Issue

When a weakref proxy was used in binary, ternary, or rich comparison operations and one of the operands turned out to be a dead proxy, the reference count of any already-unwrapped arguments was incremented by the UNWRAP macro but never released causing a memory leak of ~1 ref per call.

This affected ~20 binary operators (+, -, *, /, |, &, ^, etc.), ternary pow(), and rich comparisons.

Reproducer showing ~1 leaked ref per call on the main branch:

Fix

  • Replaced the UNWRAP macro with a proper inline function _proxy_unwrap() that tracks whether each argument was successfully incref'd via a did_incref flag.
  • Introduced goto clean_up error paths in WRAP_BINARY, WRAP_TERNARY, and proxy_richcompare that correctly Py_DECREF any already-acquired references before returning NULL.
  • Also migrated WRAP_UNARY and WRAP_METHOD to use _proxy_unwrap() for consistency. No ref leak is observed in those paths today, but dependent changes in the mainline would fail without this migration since they rely on the new unwrap function rather than the old macro.

Validation:

Reproducer script -> https://gist.github.com/prakashsellathurai/ea7ba0ec8a5cf049881464d34de31411

before (mainline )

(venv) PS C:\Users\Prakash\Documents\work\projects\mainline> .\python.bat ..\cpython\tmp\final-test.py
Running Debug|x64 interpreter...
binary +: leaked 10003 refs (~1/call)
ternary pow: leaked 10003 refs (~1/call)
compare ==: leaked 10003 refs (~1/call)

After this change

(venv) PS C:\Users\Prakash\Documents\work\projects\cpython> .\python.bat  .\tmp\final-test.py
Running Debug|x64 interpreter...
binary +: leaked 3 refs (~0/call)
ternary pow: leaked 3 refs (~0/call)
compare ==: leaked 3 refs (~0/call)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need such a long description, usually just one sentence

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants