summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko2007-05-31 15:56:10 +0000
committerDenis Vlasenko2007-05-31 15:56:10 +0000
commit22a9a3c6f874b4741f9e4193e2b9b54c9eb39bdc (patch)
treecba198adefc5030fee5c04009a2591b05e0e6b59
parenta1d24a0b6e18352930701bdff68c7f88e474c4cf (diff)
downloadbusybox-22a9a3c6f874b4741f9e4193e2b9b54c9eb39bdc.zip
busybox-22a9a3c6f874b4741f9e4193e2b9b54c9eb39bdc.tar.gz
less: fix very obscure memory corruption bug
-rw-r--r--miscutils/less.c45
1 files changed, 38 insertions, 7 deletions
diff --git a/miscutils/less.c b/miscutils/less.c
index d6b71b9..58c1ec2 100644
--- a/miscutils/less.c
+++ b/miscutils/less.c
@@ -204,7 +204,27 @@ static void fill_match_lines(unsigned pos);
#define fill_match_lines(pos) ((void)0)
#endif
-
+/* Devilishly complex routine.
+ *
+ * Has to deal with EOF and EPIPE on input,
+ * with line wrapping, with last line not ending in '\n'
+ * (possibly not ending YET!), with backspace and tabs.
+ *
+ * Variables used:
+ * flines[] - array of lines already read. Linewrap may cause
+ * one source file line to occupy several flines[n].
+ * flines[max_fline] - last line, possibly incomplete.
+ * terminated - 1 if flines[max_fline] is 'terminated'
+ * (if there was '\n' [which isn't stored itself, we just remember
+ * that it was seen])
+ * max_lineno - last line's number, this one doesn't increment
+ * on line wrap, only on "real" new lines.
+ * readbuf[0..readeof-1] - small preliminary buffer.
+ * readbuf[readpos] - next character to add to current line.
+ * linepos - screen line position of next char to be read
+ * (takes into account tabs and backspaces)
+ * eof_error - < 0 error, == 0 EOF, > 0 not EOF/error
+ */
static void read_lines(void)
{
#define readbuf bb_common_bufsiz1
@@ -225,6 +245,7 @@ static void read_lines(void)
cp += 8;
strcpy(current_line, cp);
p += strlen(current_line);
+ /* linepos is still valid from previous read_lines() */
} else {
linepos = 0;
}
@@ -275,17 +296,27 @@ static void read_lines(void)
if (c == '\x8' && linepos && p[-1] != '\t') {
readpos++; /* eat it */
linepos--;
+ /* was buggy (p could end up <= current_line)... */
*--p = '\0';
continue;
}
- if (c == '\t')
- linepos += (linepos^7) & 7;
- linepos++;
- if (linepos >= w)
- break;
+ {
+ size_t new_linepos = linepos + 1;
+ if (c == '\t') {
+ new_linepos += 7;
+ new_linepos &= (~7);
+ }
+ if (new_linepos >= w)
+ break;
+ linepos = new_linepos;
+ }
/* ok, we will eat this char */
readpos++;
- if (c == '\n') { terminated = 1; break; }
+ if (c == '\n') {
+ terminated = 1;
+ linepos = 0;
+ break;
+ }
/* NUL is substituted by '\n'! */
if (c == '\0') c = '\n';
*p++ = c;