[Bug stdio/21004] fread/fwrite does not handle EINTR correctly

egmont at gmail dot com sourceware-bugzilla@sourceware.org
Mon Dec 2 14:00:43 GMT 2024


https://sourceware.org/bugzilla/show_bug.cgi?id=21004

Egmont Koblinger <egmont at gmail dot com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |egmont at gmail dot com

--- Comment #10 from Egmont Koblinger <egmont at gmail dot com> ---
The other day it occurred to me whether printf() retried on EINTR. I was
surprised to see that it doesn't, and surprised to find extremely few relevant
web pages.

A reproducible example:

------ printf-eintr.c ------

#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>

#define PIPE_BUFFER_SIZE (64*1024)  /* measured on Ubuntu 24.10 */

char buf[PIPE_BUFFER_SIZE + 100];
char truncstr[] = "Will this string be truncated?";

void sighandler(int signum) {
    write(2, "[SIGNAL]", 8);
}

int main() {
    struct sigaction sa;
    memset(&sa, 0, sizeof(sa));
    sa.sa_handler = sighandler;
    sigaction(SIGWINCH, &sa, NULL);

    memset(buf, 'X', sizeof(buf));
    memcpy(buf + PIPE_BUFFER_SIZE - 24, truncstr, strlen(truncstr));

    int retval = printf("%s\n", buf);
    fflush(stdout);
    printf("...was it?\n");
    printf("retval was %d\n", retval);
}

----------------------------

./printf-eintr | (sleep 10; cat)

and then resize the terminal window once within 10 seconds (only once in order
not to break subsequent printf()s, just the one I'm demonstrating the problem
with). Of course any other signal is fine if you adjust the code, but probably
WINCH is the most convenient to deliver.

Output is:

[SIGNAL]XXXXXX[------ snip ------]XXXXXXWill this string be trun...was it?
retval was 65637

The "Will this string be truncated?" string, crossing the 64k boundary, was
obviously truncated. printf()'s return value did not reflect this, it pretended
everything went okay (additional 100 bytes plus newline).

printf(), unlike write() and friends, is by design unable to return partial
success and continue from there. Unlike with write(), an interface where the
user would have to continue would be extremely cumbersome to use, totally
defeating the purpose of these printf()-like convenience methods.

Do POSIX and perhaps other relevant standards not say something about this?

We have one linked bugreport about real-life occurrance of this issue, but I
suspect there might be many-many more subtle ones where an application can be
driven into a silent data loss. After all, all this example code does is prints
lots of stuff using standard high-level stdio methods, which is piped into a
slow consumer; combined with a non-SA_RESTART signal.

If printf() and friends retried, comment 4 shows that it could break (block)
some apps, but comment 5 shows that those apps are already broken, subject to a
race condition where the signal goes unnoticed. How acceptable would it be to
turn one kind of breakage into another kind? Or, if it's somewhat problematic,
would it be possible to introduce an environment variable that reverts to the
old, conceptually broken behavior, while fixing stdio methods to retry by
default?

Or, if no fix is desireable, should this bug at least be mentioned in the
manual pages of sigaction(2)/signal(7) as well as all the stdio ones? (Or, is
it already and I just missed it?) Developers could make an informed decision
whether not to fully reliable write out all the data, or whether not to use
stdio, or whether (the most likely choice I guess) not to have non-SA_RESTART
signals.

Currently this a silent data loss bug that presumably very few developers know
about, potentially affecting a plethora of utilities out there. Even if the fix
is somewhat painful, as it would cause a new kind of breakage in some already
broken utilities, I think it's still better than staying with this hardly-known
sneaky bug forever.

-- 
You are receiving this mail because:
You are on the CC list for the bug.


More information about the Glibc-bugs mailing list