Hi,

  schwarze@isnote $ cat rs.c | rs -H
  61 line 1
  [...]
  25 line 50
  26 line 12338
  Segmentation fault (core dumped) 

rs(1) -H always segfaults for input larger than 4 KB.
The reason is that, in get_line(),

 * Initially, (irows == 0), curline gets set to the static buffer ibuf.
 * -H sets DETAILSHAPE sets putlength.
 * curline keeps getting advanced by "curline += curlen + 1;".
 * Due to putlength, we never get to malloc, curline just grows until boom.

We could summarize this as follows:

  /* don't waste storage, better overrun the static buffer */

Rather than figuring out how the hand-rolled parsing loop was
intended, i decided to use the standard getline(3) interface,
making the code much more readable and eight lines shorter.
This requires switching curlen and maxlen to ssize_t, which is the
natural data type for line lengths, anyway.

While here, also add the missing error handling when the input
ends prematurely.  That caused bogus blank lines on output for

  schwarze@isnote $ echo -n | rs -K 10
  [ ten blank lines ]

It is OK to just return from getfile() because the next function,
prepfile(), will exit right away if !nelem.

OK?
  Ingo


Index: rs.c
===================================================================
RCS file: /cvs/src/usr.bin/rs/rs.c,v
retrieving revision 1.27
diff -u -p -r1.27 rs.c
--- rs.c        9 Oct 2015 01:37:08 -0000       1.27
+++ rs.c        10 Nov 2015 02:29:28 -0000
@@ -67,10 +67,10 @@ char        **elem;
 char   **endelem;
 char   *curline;
 int    allocsize = BUFSIZ;
-int    curlen;
+ssize_t        curlen;
 int    irows, icols;
 int    orows, ocols;
-int    maxlen;
+ssize_t        maxlen;
 int    skip;
 int    propgutter;
 char   isep = ' ', osep = ' ';
@@ -118,11 +118,13 @@ getfile(void)
        char **padto;
 
        while (skip--) {
-               get_line();
+               if (get_line() == EOF)
+                       return;
                if (flags & SKIPPRINT)
                        puts(curline);
        }
-       get_line();
+       if (get_line() == EOF)
+               return;
        if (flags & NOARGS && curlen < owidth)
                flags |= ONEPERLINE;
        if (flags & ONEPERLINE)
@@ -303,37 +305,29 @@ prepfile(void)
                nelem = n;
 }
 
-#define        BSIZE   2048
-char   ibuf[BSIZE];            /* two screenfuls should do */
-
 int
 get_line(void) /* get line; maintain curline, curlen; manage storage */
 {
-       static  int putlength;
-       static  char *endblock = ibuf + BSIZE;
-       char *p;
-       int c, i;
+       static  char    *ibuf = NULL;
+       static  size_t   ibufsz = 0;
 
-       if (!irows) {
-               curline = ibuf;
-               putlength = flags & DETAILSHAPE;
-       }
-       else if (skip <= 0) {                   /* don't waste storage */
-               curline += curlen + 1;
-               if (putlength)          /* print length, recycle storage */
-                       printf(" %d line %d\n", curlen, irows);
-       }
-       if (!putlength && endblock - curline < BUFSIZ) {   /* need storage */
-               if (!(curline = malloc(BSIZE)))
-                       errx(1, "File too large");
-               endblock = curline + BSIZE;
+       if (irows > 0 && flags & DETAILSHAPE)
+               printf(" %zd line %d\n", curlen, irows);
+
+       if ((curlen = getline(&ibuf, &ibufsz, stdin)) == EOF) {
+               if (ferror(stdin))
+                       err(1, NULL);
+               return EOF;
        }
-       for (p = curline, i = 1; i < BUFSIZ; *p++ = c, i++)
-               if ((c = getchar()) == EOF || c == '\n')
-                       break;
-       *p = '\0';
-       curlen = i - 1;
-       return(c);
+       if (curlen > 0 && ibuf[curlen - 1] == '\n')
+               ibuf[--curlen] = '\0';
+
+       if (skip >= 0 || flags & SHAPEONLY)
+               curline = ibuf;
+       else if ((curline = strdup(ibuf)) == NULL)
+               err(1, NULL);
+
+       return 0;
 }
 
 char **

Reply via email to