Your message dated Fri, 15 Jun 2007 18:09:42 +0200 with message-id <20070615160942.GD28554@artemis.intersec.eu> and subject line Bug#429021: libc6: fputs can lose data in buffer on signal has caused the attached Bug report to be marked as done. This means that you claim that the problem has been dealt with. If this is not the case it is now your responsibility to reopen the Bug report if necessary, and/or fix the problem forthwith. (NB: If you are a system administrator and have no idea what I am talking about this indicates a serious mail system misconfiguration somewhere. Please contact me immediately.) Debian bug tracking system administrator (administrator, Debian Bugs database)
--- Begin Message ---
- To: Debian Bug Tracking System <submit@bugs.debian.org>
- Subject: libc6: fputs can lose data in buffer on signal
- From: Dmitry Potapov <dpotapov@gmail.com>
- Date: Fri, 15 Jun 2007 17:10:59 +0400
- Message-id: <[🔎] 20070615131059.32618.19942.reportbug@localhost>
Package: libc6 Version: 2.3.6.ds1-13 Severity: important fputs (and probably other FILE based output functions) can lose previously written data that were accumulated in the user space buffer when a signal arrives. Here is an example that demonstrates the problem: # cat t.c //////////////////////////////////////// #include <stdio.h> #include <signal.h> #include <unistd.h> #include <string.h> #include <errno.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> void handler(int sig) { char buffer[80]; snprintf(buffer, sizeof(buffer), "signal handler called, sig=%d\n", sig); write(2, buffer, strlen(buffer)); } static int main_pid; #define MYSIGNUM SIGINT int reader(int fd) { char buffer[1024]; ssize_t count; size_t num_bytes, num_lines; sleep (1); kill (main_pid, MYSIGNUM); sleep (1); num_bytes = num_lines = 0; while ((count = read(fd, buffer, sizeof(buffer))) > 0) { char* p; for (p=buffer; p!=buffer+count; p++) if (*p =='\n') num_lines++; num_bytes += count; } if (count < 0) { perror ("read"); return 1; } printf ("reader: num_bytes=%d num_lines=%d\n", num_bytes, num_lines); if (num_bytes != 8*10000) { printf ("reader: number of missing bytes: %d\n", 80000 - num_bytes); return 1; } close(fd); return 0; } int writer(int fd) { int i; size_t num_bytes, num_lines; FILE* f = fdopen(fd, "w"); if (f == NULL) { perror ("fdopen"); return 1; } num_bytes = num_lines = 0; for (i=0; i<10001; i++) if (fputs ("test...\n", f) == EOF) { printf ("error at num_bytes=%d\n", num_bytes); perror("fputs"); } else { num_bytes += 8; num_lines ++; } if (fclose(f) == EOF) { perror("fclose"); return 1; } printf ("writer: num_bytes=%d num_lines=%d\n", num_bytes, num_lines); if (num_bytes != 8*10000) { printf ("writer: expected num_bytes=80000 but was %d\n", num_bytes); return 1; } return 0; } int main() { struct sigaction sa; int filedes[2]; pid_t pid; int ret; main_pid = getpid(); sa.sa_handler = handler; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sigaction(MYSIGNUM, &sa, NULL); if (pipe(filedes)) { perror("pipe"); return 1; } pid=fork(); if (pid == -1) { perror("fork"); return 1; } if (pid==0) { close(filedes[1]); return reader(filedes[0]); } else { int status; close(filedes[0]); ret = writer(filedes[1]); wait(&status); return (ret==0 && status==0) ? 0 : 1; } } //////////////////////////////////////// # gcc -W -Wall t.c -o t && ./t signal handler called, sig=2 error at num_bytes=69632 fputs: Interrupted system call writer: num_bytes=80000 num_lines=10000 reader: num_bytes=75904 num_lines=9488 reader: number of missing bytes: 4096 -- System Information: Debian Release: 4.0 APT prefers stable APT policy: (500, 'stable') Architecture: i386 (i686) Shell: /bin/sh linked to /bin/bash Kernel: Linux 2.6.18-4-k7 Locale: LANG=ru_RU.UTF-8, LC_CTYPE=ru_RU.UTF-8 (charmap=UTF-8) Versions of packages libc6 depends on: ii tzdata 2007b-1 Time Zone and Daylight Saving Time libc6 recommends no packages. -- no debconf information
--- End Message ---
--- Begin Message ---
- To: Dmitry Potapov <dpotapov@gmail.com>, 429021-done@bugs.debian.org
- Subject: Re: Bug#429021: libc6: fputs can lose data in buffer on signal
- From: Pierre Habouzit <madcoder@debian.org>
- Date: Fri, 15 Jun 2007 18:09:42 +0200
- Message-id: <20070615160942.GD28554@artemis.intersec.eu>
- In-reply-to: <[🔎] 20070615131059.32618.19942.reportbug@localhost>
- References: <[🔎] 20070615131059.32618.19942.reportbug@localhost>
On Fri, Jun 15, 2007 at 05:10:59PM +0400, Dmitry Potapov wrote: > Package: libc6 > Version: 2.3.6.ds1-13 > Severity: important > > > fputs (and probably other FILE based output functions) can lose > previously written data that were accumulated in the user space > buffer when a signal arrives. Here is an example that demonstrates > the problem: > > # cat t.c > //////////////////////////////////////// > #include <stdio.h> > #include <signal.h> > #include <unistd.h> > #include <string.h> > #include <errno.h> > #include <sys/types.h> > #include <sys/wait.h> > #include <unistd.h> > > > void handler(int sig) > { > char buffer[80]; > > snprintf(buffer, sizeof(buffer), "signal handler called, sig=%d\n", sig); > write(2, buffer, strlen(buffer)); > } > > static int main_pid; > > #define MYSIGNUM SIGINT > > int reader(int fd) > { > char buffer[1024]; > ssize_t count; > size_t num_bytes, num_lines; > > sleep (1); > kill (main_pid, MYSIGNUM); > sleep (1); > > num_bytes = num_lines = 0; > while ((count = read(fd, buffer, sizeof(buffer))) > 0) > { > char* p; > for (p=buffer; p!=buffer+count; p++) > if (*p =='\n') > num_lines++; > num_bytes += count; > } > if (count < 0) > { > perror ("read"); > return 1; > } > printf ("reader: num_bytes=%d num_lines=%d\n", num_bytes, num_lines); > if (num_bytes != 8*10000) { > printf ("reader: number of missing bytes: %d\n", 80000 - num_bytes); > return 1; > } > close(fd); > return 0; > } > > int writer(int fd) > { > int i; > size_t num_bytes, num_lines; > FILE* f = fdopen(fd, "w"); > if (f == NULL) { > perror ("fdopen"); > return 1; > } > num_bytes = num_lines = 0; > for (i=0; i<10001; i++) > if (fputs ("test...\n", f) == EOF) > { > printf ("error at num_bytes=%d\n", num_bytes); > perror("fputs"); > } > else > { > num_bytes += 8; > num_lines ++; > } > if (fclose(f) == EOF) { > perror("fclose"); > return 1; > } > printf ("writer: num_bytes=%d num_lines=%d\n", num_bytes, num_lines); > if (num_bytes != 8*10000) { > printf ("writer: expected num_bytes=80000 but was %d\n", num_bytes); > return 1; > } > return 0; > } > > int main() { > struct sigaction sa; > int filedes[2]; > pid_t pid; > int ret; > > main_pid = getpid(); > > sa.sa_handler = handler; > sigemptyset(&sa.sa_mask); > sa.sa_flags = 0; The bug is here, you should set the flags to SA_RESTART so that interupted syscalls are restarted. If you don't do so you'll break the libio. you can check using sigaction to fetch default state that SA_RESTART is the default state for sa_flags, so you are knowingly breaking your application. THe porable way to ignore a signal is to : sigaction(SIGINT, NULL, &sa); sa.sa_handler = your_handler; sigempty(sa.sa_mask); sigaction(SIGINT, &sa, NULL); with that, when the kernel return -ESTARTSYS syscalls are restarted. -- ·O· Pierre Habouzit ··O madcoder@debian.org OOO http://www.madism.orgAttachment: pgpJGtZ9qcm19.pgp
Description: PGP signature
--- End Message ---