diff options
author | Todd C. Miller <millert@cvs.openbsd.org> | 2008-10-08 17:26:48 +0000 |
---|---|---|
committer | Todd C. Miller <millert@cvs.openbsd.org> | 2008-10-08 17:26:48 +0000 |
commit | e2f4069cfaee931d5e9fc5a92bc9223420715a24 (patch) | |
tree | 4b0cc67dd5f4847ce252b40e25c800af77622398 | |
parent | 6e6895f919d2b95da469a6c530db0853b1243891 (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.c | 75 | ||||
-rw-r--r-- | usr.bin/sed/extern.h | 8 | ||||
-rw-r--r-- | usr.bin/sed/main.c | 40 | ||||
-rw-r--r-- | usr.bin/sed/misc.c | 8 |
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) |