Repository navigation
Handle reentrant detach in TextIOWrapper.close() - #7277
Conversation
When a custom `closed` property on the underlying buffer calls `detach()` during the `file_closed()` check in `close()`, the wrapper's internal buffer becomes None. Subsequent flush/close operations then fail with AttributeError on NoneType. Add a guard after the `file_closed()` check to detect if the buffer was detached reentrantly, and return early in that case (detach has already flushed the stream). This mirrors the fix applied in CPython (https://github.com/python/cpython/issues/142594\).
📝 WalkthroughWalkthroughAdds early-return guards in the TextIOWrapper close sequence to prevent operations on a detached buffer when reentrant calls to Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
📦 Library DependenciesThe following Lib/ modules were modified. Here are their dependencies: Error: 'frozenset' object has no attribute 'discard' Legend:
|
There was a problem hiding this comment.
🧹 Nitpick comments (1)
crates/vm/src/stdlib/io.rs (1)
3796-3802: Please add a regression test for this reentrant path.A targeted test where the underlying buffer’s
closedaccessor reentrantly callsTextIOWrapper.detach()duringclose()would lock this fix in and prevent regressions.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@crates/vm/src/stdlib/io.rs` around lines 3796 - 3802, Add a regression test that exercises the reentrant detach path by creating a TextIOWrapper-like object whose closed property accessor calls TextIOWrapper.detach() during close(); the test should call the wrapper's close() and assert no panic and that buffer ends up detached (matching the vm.is_none(&zelf.lock(vm)?.buffer) early-return behavior). Locate the test near existing io tests for TextIOWrapper/close and reference the methods file_closed(), detach(), and the closed property to simulate the reentrant call and verify the early-return branch is hit.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@crates/vm/src/stdlib/io.rs`:
- Around line 3796-3802: Add a regression test that exercises the reentrant
detach path by creating a TextIOWrapper-like object whose closed property
accessor calls TextIOWrapper.detach() during close(); the test should call the
wrapper's close() and assert no panic and that buffer ends up detached (matching
the vm.is_none(&zelf.lock(vm)?.buffer) early-return behavior). Locate the test
near existing io tests for TextIOWrapper/close and reference the methods
file_closed(), detach(), and the closed property to simulate the reentrant call
and verify the early-return branch is hit.
ℹ️ Review info
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
Lib/test/test_io.pyis excluded by!Lib/**
📒 Files selected for processing (1)
crates/vm/src/stdlib/io.rs
|
@coderabbitai I have enabled test_issue142594 in this PR which does exactly what you suggested (calling wrapper.detach() inside the closed property). It should prevent regressions for this fix going forward. |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: Length of output: 0 🏁 Script executed: Length of output: 933 🏁 Script executed: Length of output: 529 🏁 Script executed: Length of output: 156 🏁 Script executed: Length of output: 491
This is exactly the issue your fix addresses! By enabling this test, you've ensured that:
This is a great way to validate the fix and maintain test coverage for this subtle reentrancy issue. The test suite will now catch any future changes that might reintroduce the AttributeError on NoneType problem. 🎉 |
When a custom `closed` property on the underlying buffer calls `detach()` during the `file_closed()` check in `close()`, the wrapper's internal buffer becomes None. Subsequent flush/close operations then fail with AttributeError on NoneType. Add a guard after the `file_closed()` check to detect if the buffer was detached reentrantly, and return early in that case (detach has already flushed the stream). This mirrors the fix applied in CPython (https://github.com/python/cpython/issues/142594\).
When a custom `closed` property on the underlying buffer calls `detach()` during the `file_closed()` check in `close()`, the wrapper's internal buffer becomes None. Subsequent flush/close operations then fail with AttributeError on NoneType. Add a guard after the `file_closed()` check to detect if the buffer was detached reentrantly, and return early in that case (detach has already flushed the stream). This mirrors the fix applied in CPython (https://github.com/python/cpython/issues/142594\).
When a custom
closedproperty on the underlying buffer callsdetach()during thefile_closed()check inclose(), the wrapper's internal buffer becomes None. Subsequent flush/close operations then fail with AttributeError on NoneType.Add a guard after the
file_closed()check to detect if the buffer was detached reentrantly, and return early in that case (detach has already flushed the stream).This mirrors the fix applied in CPython
(https://github.com/python/cpython/issues/142594\).
Summary by CodeRabbit
Bug Fixes