-
-
Notifications
You must be signed in to change notification settings - Fork 34.7k
gh-143008: Fix Null pointer dereferences in TextIOWrapper underlying stream access #145957
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
base: main
Are you sure you want to change the base?
Changes from all commits
42caa08
551c3eb
4f455f4
ec39a61
98bc865
c52559b
210b21b
150fcee
d7f14fc
df212a5
d1a1a98
009cf12
afe79c7
452168c
d7b146e
593b0ea
e5c014a
eb23eaa
2581e6c
feafb90
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 |
|---|---|---|
|
|
@@ -11,7 +11,11 @@ | |
| import weakref | ||
| from collections import UserList | ||
| from test import support | ||
| from test.support import os_helper, threading_helper | ||
| from test.support import ( | ||
| os_helper, | ||
| set_recursion_limit, | ||
| threading_helper | ||
| ) | ||
| from test.support.script_helper import assert_python_ok | ||
| from .utils import CTestCase, PyTestCase | ||
|
|
||
|
|
@@ -1560,6 +1564,53 @@ def closed(self): | |
| wrapper = self.TextIOWrapper(raw) | ||
| wrapper.close() # should not crash | ||
|
|
||
| def test_reentrant_detach_during_flush(self): | ||
| # gh-143008: Reentrant detach() during flush should not crash. | ||
| wrapper = None | ||
| wrapper_ref = lambda: None | ||
|
|
||
| class EvilBuffer(self.BufferedRandom): | ||
| detach_on_write = False | ||
|
|
||
| def flush(self): | ||
| wrapper = wrapper_ref() | ||
| if wrapper is not None and not self.detach_on_write: | ||
| wrapper.detach() | ||
| return super().flush() | ||
|
|
||
| def write(self, b): | ||
| wrapper = wrapper_ref() | ||
| if wrapper is not None and self.detach_on_write: | ||
| wrapper.detach() | ||
| return len(b) | ||
|
|
||
| # Many calls could result in the same null self->buffer crash. | ||
| tests = [ | ||
| ('truncate', lambda: wrapper.truncate(0)), | ||
| ('close', lambda: wrapper.close()), | ||
| ('detach', lambda: wrapper.detach()), | ||
| ('seek', lambda: wrapper.seek(0)), | ||
| ('tell', lambda: wrapper.tell()), | ||
| ('reconfigure', lambda: wrapper.reconfigure(line_buffering=True)), | ||
| ] | ||
| for name, method in tests: | ||
| with self.subTest(name), set_recursion_limit(100): | ||
|
Member
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. Why do you reduce the recursion limit? |
||
| wrapper = self.TextIOWrapper(EvilBuffer(self.MockRawIO()), encoding='utf-8') | ||
| wrapper_ref = weakref.ref(wrapper) | ||
| # Used to crash; now will run out of stack. | ||
| self.assertRaises(RecursionError, method) | ||
| wrapper_ref = lambda: None | ||
| del wrapper | ||
|
Comment on lines
+1602
to
+1603
Member
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. Would it work to just assign wrapper to |
||
|
|
||
| with self.subTest('read via writeflush'): | ||
| EvilBuffer.detach_on_write = True | ||
| wrapper = self.TextIOWrapper(EvilBuffer(self.MockRawIO()), encoding='utf-8') | ||
| wrapper_ref = weakref.ref(wrapper) | ||
| wrapper.write('x') | ||
| self.assertRaisesRegex(ValueError, "detached", wrapper.read) | ||
| wrapper_ref = lambda: None | ||
| del wrapper | ||
|
|
||
|
|
||
| class PyTextIOWrapperTest(TextIOWrapperTest, PyTestCase): | ||
| shutdown_error = "LookupError: unknown encoding: ascii" | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| Fix crash in :class:`io.TextIOWrapper` when reentrant | ||
| :meth:`io.TextIOBase.detach` is called reentrantly from the underlying buffer. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| Fix race conditions when re-initializing a :class:`io.TextIOWrapper` object. |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Uh oh!
There was an error while loading. Please reload this page.