[PROBLEM+PATCH] 2.X zero-length read on non-empty pipe returns EAGAIN

Julian Bradfield (jcb@daimi.au.dk)
Mon, 7 Jun 1999 12:19:44 +0200 (MDT)


[Note: I can't find a maintainer for this, which means it's probably
Linus, which means there's no email address to send patches to.
Is this the only place I need to send it? ]

This problem was observed with kernel 2.2.9 on an i386, but appears
from the source to be present in all 2.X kernels.

Description: a read() with count=0 on a pipe that is not empty
should return 0; instead it returns -1 with EAGAIN.

Reproduce by the following program:
----- begin pipebug.c -----
#include <stdio.h>

void main() {
int fds[2];
int n; char junk[10];char *data = "0123456789";

pipe(fds);
if ( fork() ) {
close(fds[1]);
sleep(5); /* just to ensure the write has happened in the child! */
n = read(fds[0],junk,0);
printf("Got %d chars\n",n);
if ( n < 0 ) perror("first read");
n = read(fds[0],junk,4);
printf("Got %d chars\n",n);
if ( n < 0 ) perror("second read");
} else {
close(fds[0]);
write(fds[1],data,4);
sleep(10) ; /* to avoid closing pipe */
}
}
----- end pipebug.c -----

Analysis: simple bug in pipe_read() in linux/fs/pipe.c.

Fix: *If* the manual page for read() is correct in saying that
a read of length zero should always return 0 and do nothing else,
then the enclosed patch is probably right. (Somebody who knows, please
check that it should indeed come after the invalid seek test---I don't
know enough about what the fs routines are defined to do.)
If on the other hand there are circumstances in which such a read
should return an error (e.g. if it is felt that the locking should
still be done), then a slightly less trivial fix is required.

Patch follows:

--- linux-2.2.9/fs/pipe.c Fri Nov 13 19:07:26 1998
+++ linux/fs/pipe.c Mon Jun 7 09:08:03 1999
@@ -25,7 +25,7 @@
/* Florian Coosmann (FGC) ^ current = 1 */
/* Additionally, we now use locking technique. This prevents race condition */
/* in case of paging and multiple read/write on the same pipe. (FGC) */
-
+/* Reads with count = 0 should always return 0. Julian Bradfield 1999-06-07. */

static ssize_t pipe_read(struct file * filp, char * buf,
size_t count, loff_t *ppos)
@@ -34,8 +34,11 @@
ssize_t chars = 0, size = 0, read = 0;
char *pipebuf;

+
if (ppos != &filp->f_pos)
return -ESPIPE;
+
+ if ( !count ) return 0;

if (filp->f_flags & O_NONBLOCK) {
if (PIPE_LOCK(*inode))

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/