This is the mail archive of the libc-alpha@sourceware.cygnus.com mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

[Keith Owens <kaos@ocs.com.au>] libc/1174: stdio without SA_RESTART loses output



Here comes another bug report - this time the problem is signal
handling.

The program writes blocks of 512 data to stdout and loses 8 such
blocks when a signal occurs.  If the program use write in a loop, it
should work with checking errno for EINTR - but the program uses
fwrite.

What needs to be done?
Andreas



Topics:
   libc/1174: stdio without SA_RESTART loses output


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

Date: Tue, 22 Jun 1999 08:55:44 +1000
From: Keith Owens <kaos@ocs.com.au>
To: bugs@gnu.org
Subject: libc/1174: stdio without SA_RESTART loses output
Message-Id: <19990621225546.387.qmail@mail.ocs.com.au>


>Number:         1174
>Category:       libc
>Synopsis:       A program using stdio and signals without SA_RESTART loses output
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    libc-gnats
>State:          open
>Class:          sw-bug
>Submitter-Id:   unknown
>Arrival-Date:   Mon Jun 21 19:00:02 EDT 1999
>Last-Modified:
>Originator:     Keith Owens
>Organization:
 O. C. Software 
>Release:        libc-2.1.1
>Environment:
Host type: i386-redhat-linux-gnu
System: Linux ocs4 2.2.10 #1 Mon Jun 14 18:11:03 EST 1999 i586 unknown
Architecture: i586

Addons: crypt glibc-compat linuxthreads
Build CFLAGS: -O3 -Wall -Winline -Wstrict-prototypes -Wwrite-strings -g
Build CC: egcs
Compiler version: egcs-2.91.66 19990314/Linux (egcs-1.1.2 release)
Kernel headers: 2.2.10
Symbol versioning: yes
Build static: yes
Build shared: yes
Build pic-default: no
Build profile: yes
Build omitfp: no
Build bounded: no
Build static-nss: no
Stdio: libio

>Description:
        A program using stdio and a signal handler which is defined
        without SA_RESTART will drop 4K chunks of output when it
        receives a signal at just the wrong time.

        This was noticed while using prcs and piping the output into a
        pager.  Sometimes the output was invalid, with large bits
        missing.  The problem was tracked to the child signal handler
        which was defined with sa_flags = 0.  Changing sa_flags to
        SA_RESTART appears to fix the problem, at least I cannot
        reproduce with SA_RESTART.

        Is it a requirement that all programs using stdio must use
        SA_RESTART on all their signal handlers?  If so, it is not
        documented anywhere that I can find.  If not, we have a bug.

>How-To-Repeat:
Compile (gcc bug.c -o bug) and run (./bug 2>&1 | less) this program.
*Slowly* scroll down the output, after about 6 seconds you will see the
"Childless!" line.  Most of the time, one or more 4K chunks of output
go missing.  Not every time, you have to hit stdio at just the right
point.  Typical output is

mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm ...
nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ...
j 24 c 512 ferror 0 errno 0
j 25 c 512 ferror 0 errno 0
j 26 c 512 ferror 0 errno 0
j 27 c 512 ferror 0 errno 0
j 28 c 512 ferror 0 errno 0
j 29 c 512 ferror 0 errno 0
j 30 c 512 ferror 0 errno 0
j 31 c 512 ferror 0 errno 0
Childless!
j 32 c 0 ferror 1 errno 4
j 32 c 512 ferror 0 errno 0
j 33 c 512 ferror 0 errno 0
j 34 c 512 ferror 0 errno 0
j 35 c 512 ferror 0 errno 0
j 36 c 512 ferror 0 errno 0
j 37 c 512 ferror 0 errno 0
j 38 c 512 ferror 0 errno 0
j 39 c 512 ferror 0 errno 0
wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww ...
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ...

With sa-flags = 0, the program sees EINTR and redrives the fwrite loop
but it looks very much as though glibc stdio is not redriving its write
loop.

It does not occur if the program writes 4K chunks (data[4096]) itself.
Neither does it occur if sa_flags are set to SA_RESTART.

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

static void chld_handler(int s)
{
  fprintf(stderr, "Childless!\n");
}

static void handle_signals(void)
{
    struct sigaction act;
    sigset_t signal_mask;

    sigemptyset(&signal_mask);

    act.sa_handler = chld_handler;
    act.sa_mask = signal_mask;
    act.sa_flags = 0;		/* 0 bad, SA_RESTART good */
    sigaction (SIGCHLD, &act, NULL);
}


int main(int argc, char **argv)
{
  char *buf, data[512];
  int i = 0, j, c, nbytes;
  char fill[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";

  handle_signals();

  if (!fork()) {
    sleep(5);
    return(0);
  }
  for (j = 0; j < 100; ++j) {
    memset(data, fill[i], sizeof(data)-1);
    data[sizeof(data)-1] = '\n';
    if (++i >= sizeof(fill))
      i = 0;
    nbytes = sizeof(data);
    buf = data;
    while (nbytes > 0) {
      do {
	errno = 0;
        clearerr(stdout);
	c = fwrite (buf, 1, nbytes, stdout);
        fprintf(stderr, "j %d c %d ferror %d errno %d\n", j, c, ferror(stdout), errno);
      } while (c <= 0 && ferror(stdout) && errno == EINTR);

    if (c <= 0 && ferror(stdout))
      return 1;

      nbytes -= c;
      buf = buf + c;
    }
  }
  return 0;
}
	
>Fix:
        Use SA_RESTART on all signal handlers in all programs using
        stdio.  If this is a permanent requirement, it needs to be
        prominently documented in both libc and stdio info/man pages.

>Audit-Trail:
>Unformatted:


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

End of forwardyKA-Cb Digest
***************************



-- 
 Andreas Jaeger   aj@arthur.rhein-neckar.de    jaeger@informatik.uni-kl.de
  for pgp-key finger ajaeger@aixd1.rhrk.uni-kl.de

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]