Skip to content

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

Open
sideeffect42 wants to merge 2 commits intopython:mainfrom
sideeffect42:fix/empty-unbuffered-write-aix
Open

gh-148773: Fix undefined behaviour in write() call#148774
sideeffect42 wants to merge 2 commits intopython:mainfrom
sideeffect42:fix/empty-unbuffered-write-aix

Conversation

@sideeffect42
Copy link
Copy Markdown

@sideeffect42 sideeffect42 commented Apr 19, 2026

write()ing zero bytes to not a regular file (e.g. stdout) is undefined behaviour and can generate a SIGHUP under certain circumstances, e.g. on AIX when running with unbuffered stdout within sudo, screen, tmux:

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

Python's print() implementation in this case calls write() twice:

# truss python3 -u -c 'print("")'
[...]
kwrite(1, 0x08001000A001B910, 0)                = 0

kwrite(1, "\n", 1)                              = 1

However, the first write() is undefined behaviour.

ssize_t write(int fildes, const void *buf, size_t nbyte);

The write() function shall attempt to write nbyte bytes from the buffer
pointed to by buf to the file associated with the open file descriptor,
fildes.

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.

https://pubs.opengroup.org/onlinepubs/9699919799/functions/write.html

write()ing zero bytes to not a regular file (e.g. stdout) is undefined behaviour
and can generate a SIGHUP under certain circumstances, e.g. on AIX when running
with unbuffered stdout within sudo, screen, tmux:

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

Python's print() implementation in this case calls write() twice:

    # truss python3 -u -c 'print("")'
    [...]
    kwrite(1, 0x08001000A001B910, 0)                = 0

    kwrite(1, "\n", 1)                              = 1

However, the first write() is undefined behaviour.

    ssize_t write(int fildes, const void *buf, size_t nbyte);

    The write() function shall attempt to write nbyte bytes from the buffer
    pointed to by buf to the file associated with the open file descriptor,
    fildes.

    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.

https://pubs.opengroup.org/onlinepubs/9699919799/functions/write.html
@bedevere-app
Copy link
Copy Markdown

bedevere-app bot commented Apr 19, 2026

Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool.

If this change has little impact on Python users, wait for a maintainer to apply the skip news label instead.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant