Repository navigation
Track Unpickler payload references during cyclic GC #9288
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,8 @@ | ||
| import _pickle | ||
| import gc | ||
| import io | ||
| import sys | ||
| import weakref | ||
| from types import MappingProxyType, MethodType | ||
|
|
||
| from testutils import assert_raises | ||
|
|
@@ -116,3 +118,42 @@ def __name__(self): | |
| with assert_raises(RuntimeError) as caught: | ||
| exec("method.__reduce__()", namespace) | ||
| assert caught.exception is name_error | ||
|
|
||
|
|
||
| # Unpickler payloads can retain a cycle through their memo proxy. | ||
| class UnpicklerCycleStream: | ||
| def __init__(self): | ||
| self.source = io.BytesIO(_pickle.dumps([1, 2, 3], protocol=4)) | ||
| self.read = self.source.read | ||
| self.readline = self.source.readline | ||
| self.peek = self.peek_bytes | ||
|
|
||
| def peek_bytes(self, size=0): | ||
| position = self.source.tell() | ||
| data = self.source.read(size) | ||
| self.source.seek(position) | ||
| return data | ||
|
|
||
|
|
||
| class UnpicklerCycleBuffers: | ||
| def __iter__(self): | ||
| return self | ||
|
|
||
| def __next__(self): | ||
| raise StopIteration | ||
|
|
||
|
|
||
| def unpickler_payload_cycle(kind): | ||
| stream = UnpicklerCycleStream() | ||
| buffers = UnpicklerCycleBuffers() | ||
| unpickler = _pickle.Unpickler(stream, buffers=buffers) | ||
| holder = stream if kind == "stream" else buffers | ||
| holder.proxy = unpickler.memo | ||
| return weakref.ref(holder) | ||
|
|
||
|
|
||
| for kind in ("stream", "buffers"): | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
For this interpreter change and the added AGENTS.md reference: AGENTS.md:L35-L35 Useful? React with 👍 / 👎. |
||
| reference = unpickler_payload_cycle(kind) | ||
| for _ in range(3): | ||
| gc.collect() | ||
| assert reference() is None, kind | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This newly added regression block changes test logic in an existing test file, but the repository's test-modification policy says test logic, data, and assertions must never be modified and limits acceptable test-file changes to adding or removing
expectedFailuredecorators; revert this block rather than landing an unsupported test-file edit.AGENTS.md reference: AGENTS.md:L278-L282
Useful? React with 👍 / 👎.