GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Hangup when printing empty string to unbuffered stdout · Issue #148773 · python/cpython

Hangup when printing empty string to unbuffered stdout #148773

New issue
Copy link
New issue
Copy link
Open
Open
Hangup when printing empty string to unbuffered stdout#148773
Copy link
Labels
OS-unsupportedinterpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)topic-IOtype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error

Description

@sideeffect42
sideeffect42
opened on Apr 19, 2026
Issue body actions

Crash report

What happened?

$ sudo python3 -u -c 'print(""); print("foo")'
Hangup

When printing an empty string to unbuffered stdout, under certain circumstances (e.g. when running on AIX under sudo, screen, tmux), the user session including the Python interpreter will terminate.

CPython versions tested on:

CPython main branch

Operating systems tested on:

Other

Output from running 'python -VV' on the command line:

Python 3.12.13 (main, Mar 6 2026, 03:56:12) [GCC 10.3.0]

Linked PRs

  • gh-148773: Fix undefined behaviour in write() call #148774

Activity

  1. sideeffect42
    added
    type-crashA hard crash of the interpreter, possibly with a core dumpA hard crash of the interpreter, possibly with a core dump
    on Apr 19, 2026
  2. cmaloney
    added
    topic-IO
    OS-unsupported
    needs backport to 3.13only security fixesonly security fixes
    needs backport to 3.14bugs and security fixesbugs and security fixes
    on Apr 19, 2026
  3. github-project-automation
    added this to Unsupported platformson Apr 19, 2026
  4. cmaloney commented on Apr 19, 2026

    @cmaloney
    cmaloney
    on Apr 19, 2026
    Contributor
    More actions

    Hi! Thanks for the issue. Reading through the PR a little bit it looks like the issue here is that the first write is of length 0 and returns 0 and the I/O stack continues after that rather than exiting?

    Length 0 is a defined behavior in the write manual page, and _Py_write_impl underlies a lot of different I/O cases across many platforms so hesitant to skip the write call. For this particular case it should be going through Buffered I/O and Text I/O which I would have expected to not do zero-length writes....

    Really hesitant to change the underlying primitive as things like zero return and 0 length is allowed and can have side effects. I am potentially open to making sure Buffered I/O doesn't call through in this case; its job is to avoid too many writes.

  5. picnixz
    added
    3.13only security fixesonly security fixes
    3.14bugs and security fixesbugs and security fixes
    interpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)
    and removed
    needs backport to 3.13only security fixesonly security fixes
    needs backport to 3.14bugs and security fixesbugs and security fixes
    3.13only security fixesonly security fixes
    3.14bugs and security fixesbugs and security fixes
    on Apr 19, 2026
  6. sideeffect42 commented on Apr 20, 2026

    @sideeffect42
    sideeffect42
    on Apr 20, 2026
    Author
    More actions

    Hi @cmaloney.
    Thank you for having a look at my PR.

    The issue is that the "I/O stack" tells the other side (the terminal) that it has hung up instead of doing nothing an continuing.

    Can you please quote the part of the write manual page which you say says length 0 is defined behaviour?
    In the manual pages for write(3) I've read it says:

    Before any action described below is taken, and if nbyte is zero and the file is a regular file, the write() function may detect and return errors as described below. In the absence of errors, or if error detection is not performed, the write() function shall return zero and have no other results. If nbyte is zero and the file is not a regular file, the results are unspecified.

    IOW: if it is writing to a regular file it may do some error checking (if it wants to), but must return 0 and have no other results (I read this as: no side effects).
    When writing to anything else it can do whatever it wants.

    Buffered I/O does not perform the write syscall for the empty string (only for the line delimiter), however unbuffered I/O (PYTHONUNBUFFERED) does, but is undefined behaviour.

  7. cmaloney commented on Apr 21, 2026

    @cmaloney
    cmaloney
    on Apr 21, 2026
    Contributor
    More actions

    From that man page quote: "the results are unspecified" which is distinct from undefined behavior.

    To be specific for this case: _Py_write is used to write to a almost every file kind across all the platforms (Windows, BSD, Linux, macOS, ...) Python ships currently. It is not guaranteed to be writing to a "regular file" (and regularly is not for various tools/utilities built on Python such as talking to I/O devices). For terminal typlically the I/O is a Pipe or TTY rather than a regular file. Unspecified just means there there is not one particular behavior that always happens.

    The PYTHONUNBUFFERED explains a bit. That flag introduces a lot of additional edge cases in the I/O stack. With it rather than a TextIOWrapper + BufferedIO + FileIO you get just a TextIOWrapper with some config + FileIO. I really wish we had a BufferedIO with zero internal byte storage for the case instead, as FileIO does not behave like other I/O primitives Python programmers are used to. For example it drops partially written buffers rather than retrying or raising an exception. The retries and exceptions are generally added by BufferedIO. Things generally "work" with TextIOWrapper + FileIO but not always. In Python 3.16 I'm hoping to get to always a BufferedIO (but a zero length buffer one) so we can get the advantages of PYTHONUNBUFFERED / open(buffering=0) without the drawbacks.

    In your particular case it sounds a lot like a TTY where each individual data packet sent gets received (and the received length 0 is misinterpreted as end of stream). FileIO (https://docs.python.org/3/library/io.html#io.FileIO) just above the _Py_write in this case I think guarantees a single write here and isn't somewhere we can elide the write of length zero either. TextIOWrapper in this case might be okay to do it at but would need to see the complexity it adds.

  8. sideeffect42 commented on Apr 21, 2026

    @sideeffect42
    sideeffect42
    on Apr 21, 2026
    Author
    More actions

    I came to exactly the same conclusion as you describe. The write("") is interpreted (rightfully?) as EOF on the other end.

    When I compare the difference in syscalls generated between "regular PYTHONBUFFERED" and PYTHONUNBUFFERED, it is that the first does not generate the write("") syscall while the unbuffered does.

    My line of thinking was to catch empty writes at the lowest layer so that we don't have to check all the different code paths whether they catch this case. And there might be new ones added which would have to be checked as well.

    However, I see your concerns. If your plan is anyway to add a zero-length BufferedIO into the unbuffered I/O stack (and it catches the empty writes which I think it does in buffered mode already), then I think it should address this bug as well which would work for me.

  9. cmaloney commented on Apr 23, 2026

    @cmaloney
    cmaloney
    on Apr 23, 2026
    Contributor
    More actions

    For 3.16 I'd really like to (far too late for my I/O plans in 3.15). In general I want open(buffer_size=0) to use BufferedIO as a layer for its behaviors (without buffer space/copy). Overarching thread for those improvements is: https://discuss.python.org/t/reworking-buffered-i-o-in-cpython/90019

    I think it's useful to keep this open / the unnecessary write of size zero in PYTHONUNBUFFERED is a good extra test case to make sure that rework solves.

  10. cmaloney
    added
    type-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
    and removed
    type-crashA hard crash of the interpreter, possibly with a core dumpA hard crash of the interpreter, possibly with a core dump
    on Apr 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    OS-unsupportedinterpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)topic-IOtype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error

    Projects

    • Unsupported platforms
      Status
      No status
      Show more project fields

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

    You are visitor 01402503 — GeezerVison does not store the pages you look up.
    Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.