Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 18 Jan 2005 12:47:01 +0300 (MSK)
From:      Yar Tikhiy <yar@comp.chem.msu.su>
To:        FreeBSD-gnats-submit@FreeBSD.org
Subject:   bin/76398: stdio can lose data in the presence of signals
Message-ID:  <200501180947.j0I9l16Y033613@stylish.chem.msu.su>
Resent-Message-ID: <200501180950.j0I9oOER077461@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help

>Number:         76398
>Category:       bin
>Synopsis:       stdio can lose data in the presence of signals
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Tue Jan 18 09:50:24 GMT 2005
>Closed-Date:
>Last-Modified:
>Originator:     Yar Tikhiy
>Release:        FreeBSD 6.0-CURRENT i386
>Organization:
Moscow State University
>Environment:
System: FreeBSD stylish.chem.msu.su 6.0-CURRENT FreeBSD 6.0-CURRENT #0: Mon Jan 10 21:00:34 MSK 2005 yar@stylish.chem.msu.su:/usr/obj/usr/src/sys/STYLISH i386

>Description:

A signal handler can be installed without the SA_RESTART flag so
that the signal will interrupt certain syscalls.  The application
should be able to restart the interrupted operation by itself if
it installs such signal handlers.  However, stdio isn't ready for
this approach.  An interrupted write call will be treated by stdio
as an unrecoverable error condition and the current buffer contents
will be lost.  This is not dictated by the design, but is due to
the manner stdio has been coded in.  See __sflush() in particular,
which is the major source of the problem.

>How-To-Repeat:

Here's a test program demonstrating the bug easily.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <err.h>
#include <errno.h>
#include <md5.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

/* #define CHILD_READER */
/* #define USE_PIPE */

#define NDATA	1000
#define	DELAY	2

void  hup(int);
void  setdata(int);
char *getdata(void);

int
main()
{
	char c, digest0[33], digest[33], *p;
	FILE *fp;
	int i, s[2];
	MD5_CTX md5;
	pid_t child;
	struct sigaction sa;

	MD5Init(&md5);
	setdata(NDATA);
	while ((p = getdata()))
		MD5Update(&md5, p, strlen(p));
	p = MD5End(&md5, digest0);
	printf("True digest is %s\n", digest0);

	sa.sa_handler = hup;
	sigemptyset(&sa.sa_mask);
	sa.sa_flags = 0;
	if (sigaction(SIGHUP, &sa, NULL) == -1)
		err(2, "sigaction");

#ifndef USE_PIPE
	if (socketpair(PF_UNIX, SOCK_STREAM, 0, s) < 0)
		err(2, "socketpair");
#else
	if (pipe(s) < 0)
		err(2, "pipe");
#endif

	switch (child = fork()) {
	case -1:
		err(2, "fork");

#ifndef CHILD_READER
	case 0:
#else
	default:
#endif
		if ((fp = fdopen(s[0], "w")) == NULL)
			err(2, "fdopen in writer");
		close(s[1]);
		setdata(NDATA);
		while ((p = getdata()))
			for (; *p; p++)
				if (fputc(*p, fp) == EOF) {
					if (errno == EINTR)
						clearerr(fp);
					else
						err(2, "fputc");
				}
		fclose(fp);
#ifdef CHILD_READER
		waitpid(child, &i, 0);
#endif
		break;

#ifndef CHILD_READER
	default:
#else
	case 0:
#endif
		close(s[0]);
		if ((fp = fdopen(s[1], "r")) == NULL)
			err(2, "fdopen in reader");
		sleep(DELAY);
#ifndef CHILD_READER
		if (kill(child, SIGHUP) == -1)
#else
		if (kill(getppid(), SIGHUP) == -1)
#endif
			err(2, "kill");
		sleep(DELAY);
		MD5Init(&md5);
		while ((i = fgetc(fp)) != EOF) {
			c = i;
			MD5Update(&md5, &c, 1);
		}
		MD5End(&md5, digest);
		printf(" Got digest of %s\n", digest);
		fclose(fp);
		break;
	}
	return (0);
}

void
hup(int signo __unused)
{
}

static int ndata, seq;

void
setdata(int n)
{
	
	ndata = n;
	seq = 0;
}

char *
getdata()
{
	static char databuf[256];

	if (seq >= ndata)
		return (NULL);
	sprintf(databuf, "%08d xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n", seq++);
	return (databuf);
}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

>Fix:

I'm trying to work one out.
>Release-Note:
>Audit-Trail:
>Unformatted:



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200501180947.j0I9l16Y033613>