Bug#429021: libc6: fputs can lose data in buffer on signal
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
Reply to: