about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog5
-rw-r--r--Src/hist.c60
2 files changed, 40 insertions, 25 deletions
diff --git a/ChangeLog b/ChangeLog
index cae28a521..bc7dcc647 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2001-09-24  Bart Schaefer  <schaefer@zsh.org>
+
+	* users/4269: Src/hist.c: Detect and reject corrupted history
+	files ('\0' bytes) rather than consuming all available memory.
+
 2001-09-24  Peter Stephenson  <pws@csr.com>
 
 	* Src/builtin.c, Src/exec.c: Unwind function calls before exiting
diff --git a/Src/hist.c b/Src/hist.c
index 6b254a3db..6ce3651dc 100644
--- a/Src/hist.c
+++ b/Src/hist.c
@@ -1766,6 +1766,33 @@ static struct {
 
 static int histfile_linect;
 
+static int readhistline(int start, char **bufp, int *bufsiz, FILE *in)
+{
+    char *buf = *bufp;
+    if (fgets(buf + start, *bufsiz - start, in)) {
+	int l = strlen(buf);
+
+	if (start >= l)
+	    return -1;
+
+	if (l) {
+	    if (buf[l - 1] != '\n' && !feof(in)) {
+		*bufp = zrealloc(buf, 2 * (*bufsiz));
+		*bufsiz = 2 * (*bufsiz);
+		return readhistline(l, bufp, bufsiz, in);
+	    }
+	    buf[l - 1] = '\0';
+	    if (l > 1 && buf[l - 2] == '\\') {
+		buf[--l - 1] = '\n';
+		if (!feof(in))
+		    return readhistline(l, bufp, bufsiz, in);
+	    }
+	}
+	return l;
+    } else
+	return 0;
+}
+
 /**/
 void
 readhistfile(char *fn, int err, int readflags)
@@ -1778,7 +1805,7 @@ readhistfile(char *fn, int err, int readflags)
     short *wordlist;
     struct stat sb;
     int nwordpos, nwordlist, bufsiz;
-    int searching, newflags;
+    int searching, newflags, l;
 
     if (!fn && !(fn = getsparam("HISTFILE")))
 	return;
@@ -1816,30 +1843,13 @@ readhistfile(char *fn, int err, int readflags)
 	if (readflags & HFILE_SKIPOLD
 	 || (hist_ignore_all_dups && newflags & hist_skip_flags))
 	    newflags |= HIST_MAKEUNIQUE;
-	while (fpos = ftell(in), fgets(buf, bufsiz, in)) {
-	    int l = strlen(buf);
-	    char *pt;
-
-	    while (l) {
-		while (buf[l - 1] != '\n') {
-		    buf = zrealloc(buf, 2 * bufsiz);
-		    bufsiz = 2 * bufsiz;
-		    if (!fgets(buf + l, bufsiz - l, in)) {
-			l++;
-			break;
-		    }
-		    l += strlen(buf+l);
-		}
-		buf[l - 1] = '\0';
-		if (l > 1 && buf[l - 2] == '\\') {
-		    buf[--l - 1] = '\n';
-		    fgets(buf + l, bufsiz - l, in);
-		    l += strlen(buf+l);
-		} else
-		    break;
-	    }
+	while (fpos = ftell(in), (l = readhistline(0, &buf, &bufsiz, in))) {
+	    char *pt = buf;
 
-	    pt = buf;
+	    if (l < 0) {
+		zerr("corrupt history file %s", fn, 0);
+		break;
+	    }
 	    if (*pt == ':') {
 		pt++;
 		stim = zstrtol(pt, NULL, 0);
@@ -1933,7 +1943,7 @@ readhistfile(char *fn, int err, int readflags)
 
 	fclose(in);
     } else if (err)
-	zerr("can't read history file", fn, 0);
+	zerr("can't read history file %s", fn, 0);
 
     unlockhistfile(fn);
 }