bug-gnu-utils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: /dev/fd/n bug in gawk 3.1.5


From: Aharon Robbins
Subject: Re: /dev/fd/n bug in gawk 3.1.5
Date: Sun, 18 Jun 2006 22:44:53 +0300

Greetings. Re this:

> Date: Tue, 13 Jun 2006 17:49:58 -0700
> From: "John H. DuBois III" <address@hidden>
> Subject: /dev/fd/n bug in gawk 3.1.5
> To: address@hidden
>
> $ cat /dev/fd/4 /dev/fd/5 4<tm1 5<tm2
> Contents of tm1
> Contents of tm2
> $ gawk 1 /dev/fd/4 /dev/fd/5 4<tm1 5<tm2
> Contents of tm1
> Contents of tm1
>
>
> gawk: (FILENAME=/dev/fd/5 FNR=3) fatal: error reading input file `/dev/fd/4': 
> Bad file number

The bug fix I posted yesterday was incomplete. It solved the command line 
problem
but (as I suspected) bugs were still lurking, as shown by this test program.

---------------------------------------------
BEGIN {
        while (1) {
                if ((getline l1 < "/dev/fd/4") <= 0)
                        break
                print l1

                if ((getline l2 < "/dev/fd/5") <= 0)
                        break
                print l2
        }
}
---------------------------------------------

Try it with something like

        gawk -f foo.awk 4< f1 5< f2

Or by something like this:

        $ gawk 1 /dev/pid
        gawk: cmd. line:1: warning: use `PROCINFO["pid"]' instead of `/dev/pid'
        12102
        gawk: (FILENAME=/dev/pid FNR=1) fatal: error reading input file 
`(null)': Bad file descriptor

Here is a complete patch.

Thanks for helping me get this straightened out!

Arnold
------------------------- cut here --------------------------------
Sun Jun 18 22:27:25 2006  Arnold D. Robbins  <address@hidden>

        Repair internal names like /dev/user, /dev/pid, as well as /dev/fd/N,
        which have been broken for a long time but noone noticed.

        * io.c (is_internal): new macro to check for internal file like 
`/dev/user'.
        (spec_setup): Reduce to two parameters, allocate logic is always true.
        Add IOP_NO_FREE to flag.
        (pidopen, useropen): Return `IOBUF *' instead of int. Fix
        logic to test if `iop' parameter is NULL and if so to allocate it.
        (specfdopen,): Return `IOBUF *' instead of int. Fix
        logic to test if `iop' parameter is NULL and if so to allocate it.
        Don't set IOP_NO_FREE in flag.
        (iop_open): Remove `IOBUF iob' field from `struct internal' and its use
        and the use of `spec_setup' from the code here. Change the check in the
        call to the open function to look for NULL.
        (get_a_record): Use `is_internal' in initial check for filling the
        buffer to not try to call `read' on internal files. If true, set
        the IOP_AT_EOF in the flag and return EOF.

--- ../gawk-3.1.5/io.c  2005-07-26 21:07:43.000000000 +0300
+++ io.c        2006-06-18 22:31:08.076682904 +0300
@@ -110,6 +110,7 @@
 #define at_eof(iop)     ((iop->flag & IOP_AT_EOF) != 0)
 #define has_no_data(iop)        (iop->dataend == NULL)
 #define no_data_left(iop)      (iop->off >= iop->dataend)
+#define is_internal(iop) ((iop->flag & IOP_IS_INTERNAL) != 0)
 /* The key point to the design is to split out the code that searches through 
*/
 /* a buffer looking for the record and the terminator into separate routines, 
*/
 /* with a higher-level routine doing the reading of data and buffer 
management. */
@@ -163,10 +164,10 @@
 static int gawk_pclose P((struct redirect *rp));
 static int do_pathopen P((const char *file));
 static int str2mode P((const char *mode));
-static void spec_setup P((IOBUF *iop, int len, int allocate));
-static int specfdopen P((IOBUF *iop, const char *name, const char *mode));
-static int pidopen P((IOBUF *iop, const char *name, const char *mode));
-static int useropen P((IOBUF *iop, const char *name, const char *mode));
+static void spec_setup P((IOBUF *iop, int len));
+static IOBUF *specfdopen P((IOBUF *iop, const char *name, const char *mode));
+static IOBUF *pidopen P((IOBUF *iop, const char *name, const char *mode));
+static IOBUF *useropen P((IOBUF *iop, const char *name, const char *mode));
 static int two_way_open P((const char *str, struct redirect *rp));
 static int pty_vs_pipe P((const char *command));
 
@@ -1422,30 +1423,24 @@
 /* spec_setup --- setup an IOBUF for a special internal file */
 
 static void
-spec_setup(IOBUF *iop, int len, int allocate)
+spec_setup(IOBUF *iop, int len)
 {
        char *cp;
 
-       if (allocate) {
-               emalloc(cp, char *, len+2, "spec_setup");
-               iop->buf = cp;
-       } else {
-               len = strlen(iop->buf);
-               iop->buf[len++] = '\n'; /* get_a_record clobbered it */
-               iop->buf[len] = '\0';   /* just in case */
-       }
+       emalloc(cp, char *, len+2, "spec_setup");
+       iop->buf = cp;
        iop->off = iop->buf;
        iop->count = 0;
        iop->size = len;
        iop->end = iop->buf + len;
        iop->dataend = iop->end;
        iop->fd = -1;
-       iop->flag = IOP_IS_INTERNAL | IOP_AT_START;
+       iop->flag = IOP_IS_INTERNAL | IOP_AT_START | IOP_NO_FREE;
 }
 
 /* specfdopen --- open an fd special file */
 
-static int
+static IOBUF *
 specfdopen(IOBUF *iop, const char *name, const char *mode)
 {
        int fd;
@@ -1453,17 +1448,14 @@
 
        fd = devopen(name, mode);
        if (fd == INVALID_HANDLE)
-               return INVALID_HANDLE;
-       tp = iop_alloc(fd, name, NULL);
+               return NULL;
+       tp = iop_alloc(fd, name, iop);
        if (tp == NULL) {
                /* don't leak fd's */
                close(fd);
-               return INVALID_HANDLE;
+               return NULL;
        }
-       *iop = *tp;
-       iop->flag |= IOP_NO_FREE;
-       free(tp);
-       return 0;
+       return tp;
 }
 
 #ifdef GETPGRP_VOID
@@ -1474,7 +1466,7 @@
 
 /* pidopen --- "open" /dev/pid, /dev/ppid, and /dev/pgrpid */
 
-static int
+static IOBUF *
 pidopen(IOBUF *iop, const char *name, const char *mode ATTRIBUTE_UNUSED)
 {
        char tbuf[BUFSIZ];
@@ -1483,6 +1475,12 @@
 
        warning(_("use `PROCINFO[\"%s\"]' instead of `%s'"), cp, name);
 
+       if (iop == NULL) {
+               iop = iop_alloc(INVALID_HANDLE, name, iop);
+               if (iop == NULL)
+                       return NULL;
+       }
+
        if (name[6] == 'g')
                sprintf(tbuf, "%d\n", (int) getpgrp(getpgrp_arg()));
        else if (name[6] == 'i')
@@ -1490,9 +1488,9 @@
        else
                sprintf(tbuf, "%d\n", (int) getppid());
        i = strlen(tbuf);
-       spec_setup(iop, i, TRUE);
+       spec_setup(iop, i);
        strcpy(iop->buf, tbuf);
-       return 0;
+       return iop;
 }
 
 /* useropen --- "open" /dev/user */
@@ -1507,7 +1505,7 @@
  * supplementary group set.
  */
 
-static int
+static IOBUF *
 useropen(IOBUF *iop, const char *name ATTRIBUTE_UNUSED, const char *mode 
ATTRIBUTE_UNUSED)
 {
        char tbuf[BUFSIZ], *cp;
@@ -1515,6 +1513,12 @@
 
        warning(_("use `PROCINFO[...]' instead of `/dev/user'"));
 
+       if (iop == NULL) {
+               iop = iop_alloc(INVALID_HANDLE, name, iop);
+               if (iop == NULL)
+                       return NULL;
+       }
+
        sprintf(tbuf, "%d %d %d %d", (int) getuid(), (int) geteuid(), (int) 
getgid(), (int) getegid());
 
        cp = tbuf + strlen(tbuf);
@@ -1529,9 +1533,9 @@
        *cp++ = '\0';
 
        i = strlen(tbuf);
-       spec_setup(iop, i, TRUE);
+       spec_setup(iop, i);
        strcpy(iop->buf, tbuf);
-       return 0;
+       return iop;
 }
 
 /* iop_open --- handle special and regular files for input */
@@ -1544,8 +1548,7 @@
        static struct internal {
                const char *name;
                int compare;
-               int (*fp) P((IOBUF *, const char *, const char *));
-               IOBUF iob;
+               IOBUF *(*fp) P((IOBUF *, const char *, const char *));
        } table[] = {
                { "/dev/fd/",           8,      specfdopen },
                { "/dev/stdin",         10,     specfdopen },
@@ -1570,12 +1573,7 @@
 
                for (i = 0; i < devcount; i++) {
                        if (STREQN(name, table[i].name, table[i].compare)) {
-                               iop = & table[i].iob;
-
-                               if (iop->buf != NULL) {
-                                       spec_setup(iop, 0, FALSE);
-                                       return iop;
-                               } else if ((*table[i].fp)(iop, name, mode) == 0)
+                               if ((iop = (*table[i].fp)(iop, name, mode)) != 
NULL)
                                        return iop;
                                else {
                                        warning(_("could not open `%s', mode 
`%s'"),
@@ -2906,6 +2908,10 @@
 
         /* <fill initial buffer>=                                              
     */
         if (has_no_data(iop) || no_data_left(iop)) {
+               if (is_internal(iop)) {
+                       iop->flag |= IOP_AT_EOF;
+                       return EOF;
+               }
                 iop->count = read(iop->fd, iop->buf, iop->readsize);
                 if (iop->count == 0) {
                         iop->flag |= IOP_AT_EOF;




reply via email to

[Prev in Thread] Current Thread [Next in Thread]