Skip to content

gh-132962: _pyrepl: Prevent crash on Windows when stdout is redirected #135456

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

Open
wants to merge 17 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
93c04f9
gh-132962: _pyrepl: Prevent crash on Windows when stdout is redirected
shuimu5418 Jun 13, 2025
d8cc913
Add a test case to test_windows_console.py
shuimu5418 Jun 14, 2025
2e945fe
Replace sleep() with timeout in test case
shuimu5418 Jun 14, 2025
459232d
Fix formatting errors and make it pass CI tests
shuimu5418 Jun 14, 2025
7a8778d
gh-135371: Fix asyncio introspection output to include internal corou…
pablogsal Jun 14, 2025
67d3adc
gh-135504: Document `LIBZSTD_CFLAGS` and `LIBZSTD_LIBS` config option…
sobolevn Jun 14, 2025
df6e5b3
gh-135497: fix `MAXLOGNAME` detection in `configure.ac` (#135508)
alebcay Jun 14, 2025
73b6ea2
gh-135171: Update documentation for the generator expression (GH-135351)
serhiy-storchaka Jun 15, 2025
67c853f
gh-127319: Disable port reuse on HTTP, XMLRPC, and logging TCP server…
jeremycline Jun 15, 2025
2e71605
gh-65697: Improved error msg for configparser key validation (#135527)
lincolnj1 Jun 15, 2025
017aeab
gh-135371: Clean tags from pointers in all cases in remote debugging …
pablogsal Jun 15, 2025
e170848
gh-135361: update documentation for `remote_debugger_script` audit ev…
Zheaoli Jun 15, 2025
34e85c3
gh-111178: fix UBSan failures for `RemoteUnwinderObject` (#135539)
picnixz Jun 15, 2025
c4c7a98
gh-67022: Document bytes/str inconsistency in email.header.decode_hea…
dlenski Jun 15, 2025
062a483
Fix test
shuimu5418 Jun 16, 2025
3ae08fa
Fix CI
shuimu5418 Jun 16, 2025
fbcc6b1
Merge branch 'main' into fix-gh-132962-win-repl-redirect
shuimu5418 Jun 16, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Lib/_pyrepl/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
raise RuntimeError("Windows 10 TH2 or later required")
if not os.isatty(sys.stdin.fileno()):
raise OSError(errno.ENOTTY, "tty required", "stdin")
if sys.platform == "win32" and not os.isatty(sys.stdout.fileno()):
raise OSError(errno.ENOTTY, "tty required", "stdout")
from .simple_interact import check
if err := check():
raise RuntimeError(err)
Expand Down
32 changes: 32 additions & 0 deletions Lib/test/test_pyrepl/test_windows_console.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
raise unittest.SkipTest("test only relevant on win32")


import subprocess
from tempfile import TemporaryDirectory
import os
import itertools
from functools import partial
from test.support import force_not_colorized_test_class
Expand Down Expand Up @@ -577,5 +580,34 @@ def test_up_vt(self):
self.assertEqual(self.mock.call_count, 3)


class WindowsCommandLineTests(unittest.TestCase):
def test_for_crash_traceback_with_redirected_stdout(self):
"""python.bat -i -c "print('hlwd')" > file.txt"""
script_command = "print('script has run')"
with TemporaryDirectory() as tmp_dir:
stdout_path = os.path.join(tmp_dir, "WinCMDLineTests.txt")
with open(stdout_path, "w") as stdout_file, \
subprocess.Popen(
[sys.executable, '-i', '-c', script_command],
stdin=None,
stdout=stdout_file,
stderr=subprocess.PIPE,
text=True, errors='replace'
) as process:
stderr_output = ""
try:
process.wait(timeout=3)
except subprocess.TimeoutExpired:
process.kill()
_, stderr_output = process.communicate()
has_crash_traceback = (
"OSError" in stderr_output and
len(stderr_output) > 1200
)
if has_crash_traceback:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I said earlier, we should avoid exercising the bug, and instead exercise the correct behavior. There's no need for explicit detection of the infinite traceback.

We should just call process.wait() without a timeout, and then assert that script has run is in the stdout.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We used the -i parameter, so if proc.wait() is called, Python will wait forever. There's not much I can do about this. However, exercising the correct behavior is absolutely possible. Thanks.

self.fail("Detected endless OSError traceback."
f"\n--- stderr ---\n{stderr_output[:1200]}")


if __name__ == "__main__":
unittest.main()
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
The interactive interpreter (-i) on Windows no longer crashes when standard
output is redirected. It now correctly falls back to the basic REPL in this
situation.
Loading