gh-154594: Fix copy.deepcopy() re-copying objects whose __deepcopy__ returns None - #154819
Open
sreehariannam wants to merge 1 commit into
Open
gh-154594: Fix copy.deepcopy() re-copying objects whose __deepcopy__ returns None#154819sreehariannam wants to merge 1 commit into
sreehariannam wants to merge 1 commit into
Conversation
…opy__ returns None deepcopy() used None both as the memo dict's "not cached" sentinel and as a value callers can legitimately store there, so a __deepcopy__ that returns None was indistinguishable from a cache miss and got invoked again on every subsequent reference to the same object. Use a direct memo[d] lookup (matching the existing pattern in _deepcopy_tuple/_deepcopy_frozendict) instead of memo.get(d, None), so every return value -- including None -- is memoized correctly. This also avoids reintroducing the non-immortal-sentinel refcount contention under free-threading that pythongh-132657/pythongh-138429 fixed, since no sentinel object is used at all.
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.
Fixes gh-154594.
copy.deepcopy()usesmemo.get(d, None)to check the memo dict, treatingNoneboth as the "not cached" sentinel and as a value a__deepcopy__can legitimately return. When an object's__deepcopy__returnsNone, the memo hit is indistinguishable from a miss, so the object gets deep-copied again on every subsequent reference instead of once:This was introduced by gh-132657 / GH-138429, which replaced the previous
_nil = []sentinel withNonespecifically becauseNoneis an immortal singleton in CPython, avoiding refcount contention under free-threading that a plain sentinel object would reintroduce.Rather than reintroducing a sentinel object (which would bring back that contention) or special-casing
None, this switches the lookup tomemo[d]guarded bytry/except KeyError, matching the pattern already used a few lines down in_deepcopy_tupleand_deepcopy_frozendict. This distinguishes every possible cached value (includingNone) from a genuine cache miss without any shared sentinel object.Added a regression test and a changelog entry.