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 **