You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@pratheekhassan21, sure, I think this is not a difficult issue. I think implementing Drop for a Stdout object in a manner that can't panic is the ideal implementation stragtegy. If not just creating a dummy object with a lifetime equivalent to the VM that flushes stdout on it's drop.
I tried to investigate this issue a little bit before making a contribution so maybe I can summarize what I did and my thoughts. First Here is the test that we want to make it pass:
# TODO: RUSTPYTHON@unittest.expectedFailuredeftest_stdout_flush_at_shutdown(self):
# Issue #5319: if stdout.flush() fails at shutdown, an error should# be printed out.code="""if 1: import os, sys, test.support test.support.SuppressCrashReport().__enter__() sys.stdout.write('x') os.close(sys.stdout.fileno())"""rc, out, err=assert_python_failure('-c', code)
self.assertEqual(b'', out)
self.assertEqual(120, rc)
self.assertRegex(err.decode('ascii', 'ignore'),
'Exception ignored in.*\nOSError: .*')
so basically since stdout is normally buffered (unless explicitly told to not be with -u) then when the interpreter flushes right before exit it should trigger an Error like this in Cpython:
omarabdelgawad@omarabdelgawad:~$ pythonPython 3.12.3 (main, Aug 14 2025, 17:47:21) [GCC 13.3.0] on linuxType "help", "copyright", "credits" or "license" for more information.>>> from test.support.script_helper import assert_python_failure>>> code = """if 1:... import os, sys, test.support... test.support.SuppressCrashReport().__enter__()... sys.stdout.write('x')... os.close(sys.stdout.fileno())""">>> rc,out,err = assert_python_failure('-c',code)>>> rc120>>> outb''>>> errb"Exception ignored in: <_io.TextIOWrapper name='<stdout>' mode='w' encoding='utf-8'>\nOSError: [Errno 9] Bad file descriptor\n"
However the problem is that RustPython's Interpreter exits without an error:
omarabdelgawad@omarabdelgawad:~/my_workspace/RustPython$ cargo run --release Finished `release` profile [optimized] target(s) in 0.11s Running `target/release/rustpython`Welcome to the magnificent Rust Python 0.4.0 interpreter 😱 🖖RustPython 3.13.0Type "help", "copyright", "credits" or "license" for more information.>>>>> from test.support.script_helper import assert_python_failure>>>>> code = """if 1:..... import os, sys, test.support..... test.support.SuppressCrashReport().__enter__()..... sys.stdout.write('x')..... os.close(sys.stdout.fileno())""">>>>> rc, out , err = assert_python_failure('-c',code)Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/home/omarabdelgawad/my_workspace/projects/github_repos/RustPython/pylib/Lib/test/support/script_helper.py", line 177, in assert_python_failure return _assert_python(False, *args, **env_vars) File "/home/omarabdelgawad/my_workspace/projects/github_repos/RustPython/pylib/Lib/test/support/script_helper.py", line 151, in _assert_python res.fail(cmd_line) File "/home/omarabdelgawad/my_workspace/projects/github_repos/RustPython/pylib/Lib/test/support/script_helper.py", line 90, in fail err))AssertionError: Process return code is 0command line: ['/home/omarabdelgawad/my_workspace/projects/github_repos/RustPython/target/release/rustpython', '-X', 'faulthandler', '-I', '-c', "if 1:\n\t\timport os, sys, test.support\n\t\ttest.support.SuppressCrashReport().__enter__()\n\t\tsys.stdout.write('x')\n\t\tos.close(sys.stdout.fileno())"]stdout:------stderr:------
Now I think that the interpreter flushes the stdout and stderr before exiting but probably the problem in handling them after they are closed (Bad file descriptor). so in vm/src/vm/interpreter.rs finalize function it should catch an exception in the following line no?
pubfnfinalize(self,exc:Option<PyBaseExceptionRef>) -> u8{self.enter(|vm| {
vm.flush_std();// See if any exception leaked out:let exit_code = ifletSome(exc) = exc {
vm.handle_exit_exception(exc)}else{0};
...// more stuff here as well
...
exit_code})}
Anyways on a side note I found that the REPL crashes after os.close(1) which is the same as os.close(sys.stdout.fileno()) while CPython doesn't crash:
omarabdelgawad@omarabdelgawad:~$ pythonPython 3.12.3 (main, Aug 14 2025, 17:47:21) [GCC 13.3.0] on linuxType "help", "copyright", "credits" or "license" for more information.>>> import os>>> os.close(1)>>> print("Hello")Traceback (most recent call last): File "<stdin>", line 1, in <module>OSError: [Errno 9] Bad file descriptor
while RustPython crashes
omarabdelgawad@omarabdelgawad:~/my_workspace/RustPython$ ./target/debug/rustpythonWelcome to the magnificent Rust Python 0.4.0 interpreter 😱 🖖RustPython 3.13.0Type "help", "copyright", "credits" or "license" for more information.>>>>> import sys,os>>>>> os.close(sys.stdout.fileno())Readline error: Errno(EBADF)omarabdelgawad@omarabdelgawad:~/my_workspace/RustPython$
In order to continue working on this issue I need some help finding where builtin functions like sys.stdout.write and os.close are defined.
@Embers-of-the-Fire I apologize but I don't think I will be able to contribute to this issue. I just hope that my comment will help the next one who will tackle it. thanks for the hints.
Hi, I've been looking into this and traced the root cause.
Proposed approach: Modify the finalize/shutdown path in vm/src/vm/interpreter.rs to match CPython behavior: when stdout flush fails (e.g. fd closed), print an error message to stderr and return exit code 120 instead of silently succeeding. The existing vm.flush_std() call likely needs error handling added. Validate with the test at Lib/test/test_cmd_line.py#L479.
I'll open a draft PR shortly. Happy to adjust based on your preference.
Activity
pratheekhassan21 commentedon Apr 25, 2025
hey,@arihant2math i thinking of contributing to rustpython.this will be my first contribution.can i work on this issue
arihant2math commentedon Apr 25, 2025
@pratheekhassan21, sure, I think this is not a difficult issue. I think implementing
Dropfor a Stdout object in a manner that can't panic is the ideal implementation stragtegy. If not just creating a dummy object with a lifetime equivalent to the VM that flushes stdout on it's drop.pratheekhassan21 commentedon Apr 26, 2025
can u explain a little bit more in detail about the issue.As far as i understood if program is terminated it should call the flush before terminating?
arihant2math commentedon Apr 27, 2025
The following test should be fixed if this is implemented:
RustPython/Lib/test/test_cmd_line.py
Line 479 in c97f4d1
Ayomided commentedon May 12, 2025
Hello @arihant2math is there a bit more context for this issue. I would like to contribute and tackle this as my first issue.
omar-abdelgawad commentedon Sep 12, 2025
I tried to investigate this issue a little bit before making a contribution so maybe I can summarize what I did and my thoughts. First Here is the test that we want to make it pass:
so basically since stdout is normally buffered (unless explicitly told to not be with -u) then when the interpreter flushes right before exit it should trigger an Error like this in Cpython:
However the problem is that RustPython's Interpreter exits without an error:
Now I think that the interpreter flushes the stdout and stderr before exiting but probably the problem in handling them after they are closed (Bad file descriptor). so in
vm/src/vm/interpreter.rsfinalize function it should catch an exception in the following line no?Anyways on a side note I found that the REPL crashes after
os.close(1)which is the same asos.close(sys.stdout.fileno())while CPython doesn't crash:while RustPython crashes
In order to continue working on this issue I need some help finding where builtin functions like
sys.stdout.writeandos.closeare defined.Embers-of-the-Fire commentedon Feb 12, 2026
@omar-abdelgawad Some hint on native implementations:
https://github.com/python/cpython/blob/072cd7c33627a90e9399d9d880d764407584b08e/Modules/_io/textio.c#L116-L135
https://github.com/python/cpython/blob/072cd7c33627a90e9399d9d880d764407584b08e/Modules/posixmodule.c#L11692-L11717
omar-abdelgawad commentedon Feb 12, 2026
@Embers-of-the-Fire I apologize but I don't think I will be able to contribute to this issue. I just hope that my comment will help the next one who will tackle it. thanks for the hints.
majiayu000 commentedon Mar 25, 2026
Hi, I've been looking into this and traced the root cause.
Proposed approach: Modify the finalize/shutdown path in vm/src/vm/interpreter.rs to match CPython behavior: when stdout flush fails (e.g. fd closed), print an error message to stderr and return exit code 120 instead of silently succeeding. The existing vm.flush_std() call likely needs error handling added. Validate with the test at Lib/test/test_cmd_line.py#L479.
I'll open a draft PR shortly. Happy to adjust based on your preference.
majiayu000 commentedon Mar 25, 2026
I'd like to work on this. The fix involves:
flush_std()invm_object.rsto return a status code and userun_unraisableto report stdout flush errors to stderrfinalize()ininterpreter.rsto return exit code 120 when stdout flush fails (matching CPython's behavior)@unittest.expectedFailurefromtest_stdout_flush_at_shutdownOpening a draft PR shortly.
fix: Flush stdout on shutdown matching CPython behavior (RustPython#7503
fix: Flush stdout on shutdown matching CPython behavior (#7503)