gh-144475: Fix use-after-free in functools.partial.__repr__()#145395
Open
Nicolas0315 wants to merge 3 commits intopython:mainfrom
Open
gh-144475: Fix use-after-free in functools.partial.__repr__()#145395Nicolas0315 wants to merge 3 commits intopython:mainfrom
Nicolas0315 wants to merge 3 commits intopython:mainfrom
Conversation
Hold strong references to pto->args, pto->kw, and pto->fn during partial_repr() to prevent them from being freed by a user-defined __repr__() that mutates the partial object via __setstate__(). Previously, partial_repr() iterated over pto->args using a size 'n' captured before the loop, and accessed tuple items via borrowed references. If a __repr__() called during formatting invoked pto.__setstate__() with a new (smaller) args tuple, the original tuple could be freed while the loop was still iterating, leading to a heap-buffer-overflow (out-of-bounds read). The fix takes a new reference (Py_NewRef) to the args tuple, kw dict, and fn callable before using them, ensuring they stay alive regardless of any mutations to the partial object during formatting.
|
Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool. If this change has little impact on Python users, wait for a maintainer to apply the |
pythongh-144475: Add NEWS entry for functools.partial.__repr__ fix
Use inline code markup instead of :func: and :meth: roles for partial.__repr__ and __setstate__ to avoid Sphinx reference resolution failures in the docs CI.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fix a heap-buffer-overflow (use-after-free) in
functools.partial.__repr__()where a user-defined__repr__()on an argument could mutate the partial object via__setstate__(), freeing the args tuple whilepartial_repr()was still iterating over it.Root Cause
partial_repr()captured the size ofpto->argsbefore the loop and accessed tuple items via borrowed references (PyTuple_GET_ITEM). If a__repr__()called during%Rformatting invokedpto.__setstate__()with a new (smaller) args tuple, the original tuple was freed while iteration continued, causing an out-of-bounds read.Fix
Hold strong references (
Py_NewRef) topto->args,pto->kw, andpto->fnbefore iterating/using them. This ensures the underlying objects remain alive even if user code mutates the partial via__setstate__()during formatting.The same pattern is applied to:
pto->args: The positional arguments tuple iterated in the looppto->kw: The keyword arguments dict iterated viaPyDict_Nextpto->fn: The callable whose__repr__is invoked via%RReproducer (from the issue)
Fixes #144475.