summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTodd C. Miller <millert@cvs.openbsd.org>2008-10-08 17:26:48 +0000
committerTodd C. Miller <millert@cvs.openbsd.org>2008-10-08 17:26:48 +0000
commite2f4069cfaee931d5e9fc5a92bc9223420715a24 (patch)
tree4b0cc67dd5f4847ce252b40e25c800af77622398
parent6e6895f919d2b95da469a6c530db0853b1243891 (diff)
Allow sed to handle arbitrarily long lines. Also plug a memory
leak noticed in the process. Closes PR 5303. OK otto@ deraadt@
-rw-r--r--usr.bin/sed/compile.c75
-rw-r--r--usr.bin/sed/extern.h8
-rw-r--r--usr.bin/sed/main.c40
-rw-r--r--usr.bin/sed/misc.c8
4 files changed, 84 insertions, 47 deletions
diff --git a/usr.bin/sed/compile.c b/usr.bin/sed/compile.c
index a3940542432..b8ada82c4f3 100644
--- a/usr.bin/sed/compile.c
+++ b/usr.bin/sed/compile.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: compile.c,v 1.24 2007/03/20 03:50:39 tedu Exp $ */
+/* $OpenBSD: compile.c,v 1.25 2008/10/08 17:26:47 millert Exp $ */
/*-
* Copyright (c) 1992 Diomidis Spinellis.
@@ -35,7 +35,7 @@
#ifndef lint
/* from: static char sccsid[] = "@(#)compile.c 8.2 (Berkeley) 4/28/95"; */
-static const char rcsid[] = "$OpenBSD: compile.c,v 1.24 2007/03/20 03:50:39 tedu Exp $";
+static const char rcsid[] = "$OpenBSD: compile.c,v 1.25 2008/10/08 17:26:47 millert Exp $";
#endif /* not lint */
#include <sys/types.h>
@@ -147,14 +147,17 @@ static struct s_command **
compile_stream(struct s_command **link)
{
char *p;
- static char lbuf[_POSIX2_LINE_MAX + 1]; /* To save stack */
+ static char *lbuf; /* To avoid excessive malloc calls */
+ static size_t len = _POSIX2_LINE_MAX;
struct s_command *cmd, *cmd2, *stack;
struct s_format *fp;
int naddr; /* Number of addresses */
stack = 0;
+ if (!lbuf)
+ lbuf = xmalloc(len);
for (;;) {
- if ((p = cu_fgets(lbuf, sizeof(lbuf))) == NULL) {
+ if ((p = cu_fgets(&lbuf, &len)) == NULL) {
if (stack != 0)
err(COMPILE, "unexpected EOF (pending }'s)");
return (link);
@@ -428,11 +431,13 @@ static char *
compile_re(char *p, regex_t **repp)
{
int eval;
- char re[_POSIX2_LINE_MAX + 1];
+ char *re;
+ re = xmalloc(strlen(p) + 1); /* strlen(re) <= strlen(p) */
p = compile_delimited(p, re);
if (p && strlen(re) == 0) {
*repp = NULL;
+ free(re);
return (p);
}
*repp = xmalloc(sizeof(regex_t));
@@ -440,6 +445,7 @@ compile_re(char *p, regex_t **repp)
err(COMPILE, "RE error: %s", strregerror(eval, *repp));
if (maxnsub < (*repp)->re_nsub)
maxnsub = (*repp)->re_nsub;
+ free(re);
return (p);
}
@@ -451,21 +457,31 @@ compile_re(char *p, regex_t **repp)
static char *
compile_subst(char *p, struct s_subst *s)
{
- static char lbuf[_POSIX2_LINE_MAX + 1];
+ static char *lbuf;
+ static size_t len = _POSIX2_LINE_MAX;
int asize, ref, size;
char c, *text, *op, *sp;
int sawesc = 0;
+ if (!lbuf)
+ lbuf = xmalloc(len);
+
c = *p++; /* Terminator character */
if (c == '\0')
return (NULL);
s->maxbref = 0;
s->linenum = linenum;
- asize = 2 * _POSIX2_LINE_MAX + 1;
+ asize = 2 * len + 1;
text = xmalloc(asize);
size = 0;
do {
+ if (asize - size < len + 1) {
+ do {
+ asize *= 2;
+ } while (asize - size < len + 1);
+ text = xrealloc(text, asize);
+ }
op = sp = text + size;
for (; *p; p++) {
if (*p == '\\' || sawesc) {
@@ -515,11 +531,7 @@ compile_subst(char *p, struct s_subst *s)
*sp++ = *p;
}
size += sp - op;
- if (asize - size < _POSIX2_LINE_MAX + 1) {
- asize *= 2;
- text = xrealloc(text, asize);
- }
- } while (cu_fgets(p = lbuf, sizeof(lbuf)));
+ } while ((p = cu_fgets(&lbuf, &len)));
err(COMPILE, "unterminated substitute in regular expression");
/* NOTREACHED */
}
@@ -532,7 +544,7 @@ compile_flags(char *p, struct s_subst *s)
{
int gn; /* True if we have seen g or n */
long l;
- char wfile[_POSIX2_LINE_MAX + 1], *q;
+ char wfile[PATH_MAX], *q;
s->n = 1; /* Default */
s->p = 0;
@@ -609,26 +621,27 @@ compile_tr(char *p, char **transtab)
{
int i;
char *lt, *op, *np;
- char old[_POSIX2_LINE_MAX + 1];
- char new[_POSIX2_LINE_MAX + 1];
+ char *old = NULL, *new = NULL;
if (*p == '\0' || *p == '\\')
err(COMPILE,
"transform pattern can not be delimited by newline or backslash");
+ old = xmalloc(strlen(p) + 1);
p = compile_delimited(p, old);
if (p == NULL) {
err(COMPILE, "unterminated transform source string");
- return (NULL);
+ goto bad;
}
+ new = xmalloc(strlen(p) + 1);
p = compile_delimited(--p, new);
if (p == NULL) {
err(COMPILE, "unterminated transform target string");
- return (NULL);
+ goto bad;
}
EATSPACE();
if (strlen(new) != strlen(old)) {
err(COMPILE, "transform strings are not the same length");
- return (NULL);
+ goto bad;
}
/* We assume characters are 8 bits */
lt = xmalloc(UCHAR_MAX + 1);
@@ -637,7 +650,13 @@ compile_tr(char *p, char **transtab)
for (op = old, np = new; *op; op++, np++)
lt[(u_char)*op] = *np;
*transtab = lt;
+ free(old);
+ free(new);
return (p);
+bad:
+ free(old);
+ free(new);
+ return (NULL);
}
/*
@@ -647,13 +666,20 @@ static char *
compile_text(void)
{
int asize, esc_nl, size;
- char *text, *p, *op, *s;
- char lbuf[_POSIX2_LINE_MAX + 1];
+ char *lbuf, *text, *p, *op, *s;
+ size_t len = _POSIX2_LINE_MAX;
- asize = 2 * _POSIX2_LINE_MAX + 1;
+ lbuf = xmalloc(len);
+ asize = 2 * len + 1;
text = xmalloc(asize);
size = 0;
- while (cu_fgets(lbuf, sizeof(lbuf))) {
+ while (cu_fgets(&lbuf, &len)) {
+ if (asize - size < len + 1) {
+ do {
+ asize *= 2;
+ } while (asize - size < len + 1);
+ text = xrealloc(text, asize);
+ }
op = s = text + size;
p = lbuf;
EATSPACE();
@@ -667,11 +693,8 @@ compile_text(void)
*s = '\0';
break;
}
- if (asize - size < _POSIX2_LINE_MAX + 1) {
- asize *= 2;
- text = xmalloc(asize);
- }
}
+ free(lbuf);
text[size] = '\0';
return (xrealloc(text, size + 1));
}
diff --git a/usr.bin/sed/extern.h b/usr.bin/sed/extern.h
index 283b443baa4..80e359576f7 100644
--- a/usr.bin/sed/extern.h
+++ b/usr.bin/sed/extern.h
@@ -1,4 +1,4 @@
-/* * $OpenBSD: extern.h,v 1.4 2003/06/03 02:56:16 millert Exp $*/
+/* * $OpenBSD: extern.h,v 1.5 2008/10/08 17:26:47 millert Exp $*/
/*-
* Copyright (c) 1992 Diomidis Spinellis.
* Copyright (c) 1992, 1993
@@ -47,10 +47,10 @@ extern char *fname;
void cfclose(struct s_command *, struct s_command *);
void compile(void);
void cspace(SPACE *, char *, size_t, enum e_spflag);
-char *cu_fgets(char *, int);
+char *cu_fgets(char **, size_t *);
void err(int, const char *, ...);
int mf_fgets(SPACE *, enum e_spflag);
void process(void);
char *strregerror(int, regex_t *);
-void *xmalloc(u_int);
-void *xrealloc(void *, u_int);
+void *xmalloc(size_t);
+void *xrealloc(void *, size_t);
diff --git a/usr.bin/sed/main.c b/usr.bin/sed/main.c
index 7d6423f8505..63c2a6ae795 100644
--- a/usr.bin/sed/main.c
+++ b/usr.bin/sed/main.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: main.c,v 1.12 2007/10/16 20:19:27 sobrado Exp $ */
+/* $OpenBSD: main.c,v 1.13 2008/10/08 17:26:47 millert Exp $ */
/*-
* Copyright (c) 1992 Diomidis Spinellis.
@@ -38,7 +38,7 @@ static const char copyright[] =
"@(#) Copyright (c) 1992, 1993\n\
The Regents of the University of California. All rights reserved.\n";
/* from: static char sccsid[] = "@(#)main.c 8.2 (Berkeley) 1/3/94"; */
-static const char rcsid[] = "$OpenBSD: main.c,v 1.12 2007/10/16 20:19:27 sobrado Exp $";
+static const char rcsid[] = "$OpenBSD: main.c,v 1.13 2008/10/08 17:26:47 millert Exp $";
#endif /* not lint */
#include <sys/types.h>
@@ -159,12 +159,13 @@ main(int argc, char *argv[])
* together. Empty strings and files are ignored.
*/
char *
-cu_fgets(char *buf, int n)
+cu_fgets(char **outbuf, size_t *outlen)
{
static enum {ST_EOF, ST_FILE, ST_STRING} state = ST_EOF;
static FILE *f; /* Current open file */
static char *s; /* Current pointer inside string */
static char string_ident[30];
+ size_t len;
char *p;
again:
@@ -193,11 +194,22 @@ again:
goto again;
}
case ST_FILE:
- if ((p = fgets(buf, n, f)) != NULL) {
+ if ((p = fgetln(f, &len)) != NULL) {
linenum++;
- if (linenum == 1 && buf[0] == '#' && buf[1] == 'n')
+ if (len > 0 && p[len-1] == '\n')
+ len--;
+ if (len >= *outlen) {
+ do {
+ *outlen *= 2;
+ } while (len >= *outlen);
+ free(*outbuf);
+ *outbuf = xmalloc(*outlen);
+ }
+ memcpy(*outbuf, p, len);
+ (*outbuf)[len] = '\0';
+ if (linenum == 1 && p[0] == '#' && p[1] == 'n')
nflag = 1;
- return (p);
+ return (*outbuf);
}
script = script->next;
(void)fclose(f);
@@ -206,12 +218,14 @@ again:
case ST_STRING:
if (linenum == 0 && s[0] == '#' && s[1] == 'n')
nflag = 1;
- p = buf;
+ p = *outbuf;
+ len = *outlen;
for (;;) {
- if (n-- <= 1) {
- *p = '\0';
- linenum++;
- return (buf);
+ if (len-- <= 1) {
+ *outbuf = xrealloc(*outbuf, *outlen * 2);
+ p = *outbuf + *outlen - len - 1;
+ len += *outlen;
+ *outlen *= 2;
}
switch (*s) {
case '\0':
@@ -223,14 +237,14 @@ again:
script = script->next;
*p = '\0';
linenum++;
- return (buf);
+ return (*outbuf);
}
case '\n':
*p++ = '\n';
*p = '\0';
s++;
linenum++;
- return (buf);
+ return (*outbuf);
default:
*p++ = *s++;
}
diff --git a/usr.bin/sed/misc.c b/usr.bin/sed/misc.c
index ba6055d31a2..c3dbafdf8d7 100644
--- a/usr.bin/sed/misc.c
+++ b/usr.bin/sed/misc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: misc.c,v 1.7 2006/10/09 00:23:57 tedu Exp $ */
+/* $OpenBSD: misc.c,v 1.8 2008/10/08 17:26:47 millert Exp $ */
/*-
* Copyright (c) 1992 Diomidis Spinellis.
@@ -35,7 +35,7 @@
#ifndef lint
/* from: static char sccsid[] = "@(#)misc.c 8.1 (Berkeley) 6/6/93"; */
-static const char rcsid[] = "$OpenBSD: misc.c,v 1.7 2006/10/09 00:23:57 tedu Exp $";
+static const char rcsid[] = "$OpenBSD: misc.c,v 1.8 2008/10/08 17:26:47 millert Exp $";
#endif /* not lint */
#include <sys/types.h>
@@ -54,7 +54,7 @@ static const char rcsid[] = "$OpenBSD: misc.c,v 1.7 2006/10/09 00:23:57 tedu Exp
* malloc with result test
*/
void *
-xmalloc(u_int size)
+xmalloc(size_t size)
{
void *p;
@@ -67,7 +67,7 @@ xmalloc(u_int size)
* realloc with result test
*/
void *
-xrealloc(void *p, u_int size)
+xrealloc(void *p, size_t size)
{
if ((p = realloc(p, size)) == NULL)