[comp.bugs.sys5] SVR2.0 stdio bugs

gwyn@smoke.BRL.MIL (Doug Gwyn) (08/17/89)

We just discovered that the UNIX System V stdio writing routines, in three
out of four uses of the write() system call, fail to properly deal with a
short write count return, and in one case doesn't even detect an I/O error.
Here are the fixes we applied:


In libc/port/stdio/flsbuf.c:

/*	@(#)flsbuf.c	2.8	*/
...
int
_flsbuf(c, iop)
unsigned char c;
register FILE *iop;
{
    unsigned char c1;
    register int w;	/* DAG -- write() return count */
...
	/* write out an unbuffered file, if have write perm, but no EOF */
	if ( (iop->_flag & (_IONBF | _IOWRT | _IOEOF)) == (_IONBF | _IOWRT) ) {
		c1 = c;
		iop->_cnt = 0;
		while ((w = write(fileno(iop), (char *) &c1, 1)) == 0)
			;	/* DAG -- loop! */
		if (w > 0)
			return(c);
		iop->_flag |= _IOERR;
		return(EOF);
	}
...
int
_xflsbuf(iop)
register FILE *iop;
{
	register unsigned char *base;
	register int n;
	register int w;	/* DAG -- write() return count */
...
	_BUFSYNC(iop);
	while (n > 0)	/* DAG -- loop! */
		if ((w = write(fileno(iop),(char*)base,(unsigned)n)) < 0)  {
			iop->_flag |= _IOERR;
			return(EOF);
		} else {
			base += w;
			n -= w;
		}
	return(0);


In libc/port/stdio/fputs.c:

/*      <@(#)fputs.c	3.5>	*/
...
int
fputs(ptr, iop)
char *ptr;
register FILE *iop;
{
...
	}  else  {
		/* write out to an unbuffered file */
		register unsigned int cnt = strlen(ptr);
		register unsigned int r = cnt;	/* DAG -- bytes remaining */
		register int w;	/* DAG -- write() return count */

		while (r > 0)	/* DAG -- loop! */
			if ((w = write(iop->_file, ptr, r)) < 0)  {
				iop->_flag |= _IOERR;
				return(EOF);	/* DAG -- report error! */
			} else {
				ptr += w;
				r -= w;
			}
		return cnt;
	}