summaryrefslogtreecommitdiff
path: root/usr.bin/awk
diff options
context:
space:
mode:
Diffstat (limited to 'usr.bin/awk')
-rw-r--r--usr.bin/awk/FIXES27
-rw-r--r--usr.bin/awk/awk.117
-rw-r--r--usr.bin/awk/awk.h5
-rw-r--r--usr.bin/awk/awkgram.y4
-rw-r--r--usr.bin/awk/b.c20
-rw-r--r--usr.bin/awk/lex.c16
-rw-r--r--usr.bin/awk/lib.c31
-rw-r--r--usr.bin/awk/main.c4
-rw-r--r--usr.bin/awk/maketab.c10
-rw-r--r--usr.bin/awk/run.c32
-rw-r--r--usr.bin/awk/tran.c8
11 files changed, 120 insertions, 54 deletions
diff --git a/usr.bin/awk/FIXES b/usr.bin/awk/FIXES
index d1c3217d28d..04c201fd60b 100644
--- a/usr.bin/awk/FIXES
+++ b/usr.bin/awk/FIXES
@@ -1,4 +1,4 @@
-/* $OpenBSD: FIXES,v 1.30 2020/06/10 21:04:40 millert Exp $ */
+/* $OpenBSD: FIXES,v 1.31 2020/06/10 21:05:02 millert Exp $ */
/****************************************************************
Copyright (C) Lucent Technologies 1997
All Rights Reserved
@@ -26,6 +26,25 @@ THIS SOFTWARE.
This file lists all bug fixes, changes, etc., made since the AWK book
was sent to the printers in August, 1987.
+January 31, 2020:
+ Merge PR #70, which avoids use of variable length arrays. Thanks
+ to GitHub user michaelforney. Fix issue #60 ({0} in interval
+ expressions doesn't work). Thanks to Arnold Robbins.
+
+January 24, 2020:
+ A number of small cleanups from Christos Zoulas. Add the close
+ on exec flag to files/pipes opened for redirection; courtesy of
+ Arnold Robbins.
+
+January 19, 2020:
+ If POSIXLY_CORRECT is set in the environment, then sub and gsub
+ use POSIX rules for multiple backslashes. This fixes Issue #66,
+ while maintaining backwards compatibility.
+
+January 9, 2020:
+ Input/output errors on closing files are now fatal instead of
+ mere warnings. Thanks to Martijn Dekker <martijn@inlv.org>.
+
January 5, 2020:
Fix a bug in the concatentation of two string constants into
one done in the grammar. Fixes GitHub issue #61. Thanks
@@ -64,13 +83,13 @@ October 25, 2019:
October 24, 2019:
Import second round of code cleanups from NetBSD. Much thanks
- to Christos Zoulas (Github user zoulasc). Merges PR 53.
+ to Christos Zoulas (GitHub user zoulasc). Merges PR 53.
Add an optimization for string concatenation, also from
Christos.
October 17, 2019:
Import code cleanups from NetBSD. Much thanks to Christos
- Zoulas (Github user zoulasc). Merges PR 51.
+ Zoulas (GitHub user zoulasc). Merges PR 51.
October 6, 2019:
Import code from NetBSD awk that implements RS as a regular
@@ -78,7 +97,7 @@ October 6, 2019:
September 10, 2019:
Fixes for various array / memory overruns found via gcc's
- -fsanitize=unknown. Thanks to Alexander Richardson (Github
+ -fsanitize=unknown. Thanks to Alexander Richardson (GitHub
user arichardson). Merges PRs 47 and 48.
July 28, 2019:
diff --git a/usr.bin/awk/awk.1 b/usr.bin/awk/awk.1
index 770f558d1b5..84e4f057e73 100644
--- a/usr.bin/awk/awk.1
+++ b/usr.bin/awk/awk.1
@@ -1,4 +1,4 @@
-.\" $OpenBSD: awk.1,v 1.49 2020/06/10 21:02:53 millert Exp $
+.\" $OpenBSD: awk.1,v 1.50 2020/06/10 21:05:02 millert Exp $
.\"
.\" Copyright (C) Lucent Technologies 1997
.\" All Rights Reserved
@@ -726,6 +726,14 @@ Returns integer argument x shifted by n bits to the left.
.It Fn rshift x n
Returns integer argument x shifted by n bits to the right.
.El
+.Sh ENVIRONMENT
+The following environment variables affect the execution of
+.Nm :
+.Bl -tag -width POSIXLY_CORRECT
+.It Ev POSIXLY_CORRECT
+When set, behave in accordance with the standard, even when it conflicts
+with historical behavior.
+.El
.Sh EXIT STATUS
.Ex -std awk
.Pp
@@ -792,7 +800,12 @@ The
.Nm
utility is compliant with the
.St -p1003.1-2008
-specification.
+specification except that consecutive backslashes in the replacement
+string argument for
+.Fn sub
+and
+.Fn gsub
+are not collapsed.
.Pp
The flags
.Op Fl \&dV
diff --git a/usr.bin/awk/awk.h b/usr.bin/awk/awk.h
index ba604cae6a6..e010dd7184d 100644
--- a/usr.bin/awk/awk.h
+++ b/usr.bin/awk/awk.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: awk.h,v 1.21 2020/06/10 21:03:56 millert Exp $ */
+/* $OpenBSD: awk.h,v 1.22 2020/06/10 21:05:02 millert Exp $ */
/****************************************************************
Copyright (C) Lucent Technologies 1997
All Rights Reserved
@@ -61,6 +61,7 @@ extern bool safe; /* false => unsafe, true => safe */
#define RECSIZE (8 * 1024) /* sets limit on records, fields, etc., etc. */
extern int recsize; /* size of current record, orig RECSIZE */
+extern char EMPTY[]; /* this avoid -Wwritable-strings issues */
extern char **FS;
extern char **RS;
extern char **ORS;
@@ -79,8 +80,6 @@ extern int lineno; /* line number in awk program */
extern int errorflag; /* 1 if error has occurred */
extern bool donefld; /* true if record broken into fields */
extern bool donerec; /* true if record is valid (no fld has changed */
-extern char inputFS[]; /* FS at time of input, for field splitting */
-
extern int dbg;
extern const char *patbeg; /* beginning of pattern matched */
diff --git a/usr.bin/awk/awkgram.y b/usr.bin/awk/awkgram.y
index 9a59fc785aa..85034770f07 100644
--- a/usr.bin/awk/awkgram.y
+++ b/usr.bin/awk/awkgram.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: awkgram.y,v 1.12 2020/06/10 21:03:56 millert Exp $ */
+/* $OpenBSD: awkgram.y,v 1.13 2020/06/10 21:05:02 millert Exp $ */
/****************************************************************
Copyright (C) Lucent Technologies 1997
All Rights Reserved
@@ -51,7 +51,7 @@ Node *arglist = 0; /* list of args for current function */
%token <i> NL ',' '{' '(' '|' ';' '/' ')' '}' '[' ']'
%token <i> ARRAY
%token <i> MATCH NOTMATCH MATCHOP
-%token <i> FINAL DOT ALL CCL NCCL CHAR OR STAR QUEST PLUS EMPTYRE
+%token <i> FINAL DOT ALL CCL NCCL CHAR OR STAR QUEST PLUS EMPTYRE ZERO
%token <i> AND BOR APPEND EQ GE GT LE LT NE IN
%token <i> ARG BLTIN BREAK CLOSE CONTINUE DELETE DO EXIT FOR FUNC
%token <i> SUB GSUB IF INDEX LSUBSTR MATCHFCN NEXT NEXTFILE
diff --git a/usr.bin/awk/b.c b/usr.bin/awk/b.c
index 97719cf1132..687ff5015f8 100644
--- a/usr.bin/awk/b.c
+++ b/usr.bin/awk/b.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: b.c,v 1.30 2020/06/10 21:04:40 millert Exp $ */
+/* $OpenBSD: b.c,v 1.31 2020/06/10 21:05:02 millert Exp $ */
/****************************************************************
Copyright (C) Lucent Technologies 1997
All Rights Reserved
@@ -271,6 +271,8 @@ void penter(Node *p) /* set up parent pointers and leaf indices */
parent(left(p)) = p;
parent(right(p)) = p;
break;
+ case ZERO:
+ break;
default: /* can't happen */
FATAL("can't happen: unknown type %d in penter", type(p));
break;
@@ -285,6 +287,7 @@ void freetr(Node *p) /* free parse tree */
xfree(p);
break;
UNARY
+ case ZERO:
freetr(left(p));
xfree(p);
break;
@@ -444,6 +447,8 @@ void cfoll(fa *f, Node *v) /* enter follow set of each leaf of vertex v into lfo
cfoll(f,left(v));
cfoll(f,right(v));
break;
+ case ZERO:
+ break;
default: /* can't happen */
FATAL("can't happen: unknown type %d in cfoll", type(v));
}
@@ -487,6 +492,8 @@ int first(Node *p) /* collects initially active leaves of p into setvec */
b = first(right(p));
if (first(left(p)) == 0 || b == 0) return(0);
return(1);
+ case ZERO:
+ return 0;
}
FATAL("can't happen: unknown type %d in first", type(p)); /* can't happen */
return(-1);
@@ -846,6 +853,9 @@ Node *unary(Node *np)
case QUEST:
rtok = relex();
return (unary(op2(QUEST, np, NIL)));
+ case ZERO:
+ rtok = relex();
+ return (unary(op2(ZERO, np, NIL)));
default:
return (np);
}
@@ -880,7 +890,7 @@ int (xisblank)(int c)
#endif
-struct charclass {
+static const struct charclass {
const char *cc_name;
int cc_namelen;
int (*cc_func)(int);
@@ -916,7 +926,7 @@ replace_repeat(const uschar *reptok, int reptoklen, const uschar *atom,
int i, j;
uschar *buf = NULL;
int ret = 1;
- bool init_q = (firstnum == 0); /* first added char will be ? */
+ int init_q = (firstnum == 0); /* first added char will be ? */
int n_q_reps = secondnum-firstnum; /* m>n, so reduce until {1,m-n} left */
int prefix_length = reptok - basestr; /* prefix includes first rep */
int suffix_length = strlen((const char *) reptok) - reptoklen; /* string after rep specifier */
@@ -1024,7 +1034,7 @@ int relex(void) /* lexical analyzer for reparse */
static uschar *buf = NULL;
static int bufsz = 100;
uschar *bp;
- struct charclass *cc;
+ const struct charclass *cc;
int i;
int num, m;
bool commafound, digitfound;
@@ -1198,7 +1208,7 @@ rescan:
if (repeat(starttok, prestr-starttok, lastatom,
startreptok - lastatom, n, m) > 0) {
if (n == 0 && m == 0) {
- return EMPTYRE;
+ return ZERO;
}
/* must rescan input for next token */
goto rescan;
diff --git a/usr.bin/awk/lex.c b/usr.bin/awk/lex.c
index 9861c7d25b4..4e7a546d019 100644
--- a/usr.bin/awk/lex.c
+++ b/usr.bin/awk/lex.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: lex.c,v 1.17 2020/06/10 21:04:40 millert Exp $ */
+/* $OpenBSD: lex.c,v 1.18 2020/06/10 21:05:02 millert Exp $ */
/****************************************************************
Copyright (C) Lucent Technologies 1997
All Rights Reserved
@@ -44,7 +44,7 @@ typedef struct Keyword {
int type;
} Keyword;
-Keyword keywords[] ={ /* keep sorted: binary searched */
+const Keyword keywords[] = { /* keep sorted: binary searched */
{ "BEGIN", XBEGIN, XBEGIN },
{ "END", XEND, XEND },
{ "NF", VARNF, VARNF },
@@ -102,14 +102,14 @@ int peek(void);
int gettok(char **, int *);
int binsearch(char *, Keyword *, int);
-int peek(void)
+static int peek(void)
{
int c = input();
unput(c);
return c;
}
-int gettok(char **pbuf, int *psz) /* get next input token */
+static int gettok(char **pbuf, int *psz) /* get next input token */
{
int c, retc;
char *buf = *pbuf;
@@ -401,7 +401,7 @@ int string(void)
case 'r': *bp++ = '\r'; break;
case 'b': *bp++ = '\b'; break;
case 'v': *bp++ = '\v'; break;
- case 'a': *bp++ = '\007'; break;
+ case 'a': *bp++ = '\a'; break;
case '\\': *bp++ = '\\'; break;
case '0': case '1': case '2': /* octal: \d \dd \ddd */
@@ -451,7 +451,7 @@ int string(void)
}
-int binsearch(char *w, Keyword *kp, int n)
+static int binsearch(char *w, const Keyword *kp, int n)
{
int cond, low, mid, high;
@@ -471,7 +471,7 @@ int binsearch(char *w, Keyword *kp, int n)
int word(char *w)
{
- Keyword *kp;
+ const Keyword *kp;
int c, n;
n = binsearch(w, keywords, sizeof(keywords)/sizeof(keywords[0]));
@@ -587,6 +587,8 @@ int input(void) /* get next lexical input character */
void unput(int c) /* put lexical character back on input */
{
+ if (c == '\n')
+ lineno--;
if (yysptr >= yysbuf + sizeof(yysbuf))
FATAL("pushed back too much: %.20s...", yysbuf);
*yysptr++ = c;
diff --git a/usr.bin/awk/lib.c b/usr.bin/awk/lib.c
index ee3e187aa77..f00a5ec856b 100644
--- a/usr.bin/awk/lib.c
+++ b/usr.bin/awk/lib.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: lib.c,v 1.32 2020/06/10 21:03:56 millert Exp $ */
+/* $OpenBSD: lib.c,v 1.33 2020/06/10 21:05:02 millert Exp $ */
/****************************************************************
Copyright (C) Lucent Technologies 1997
All Rights Reserved
@@ -31,18 +31,21 @@ THIS SOFTWARE.
#include <stdlib.h>
#include <unistd.h>
#include <stdarg.h>
+#include <limits.h>
#include "awk.h"
#include "ytab.h"
+char EMPTY[] = { '\0' };
FILE *infile = NULL;
-char *file = "";
+char *file = EMPTY;
char *record;
int recsize = RECSIZE;
char *fields;
int fieldssize = RECSIZE;
Cell **fldtab; /* pointers to Cells */
-char inputFS[100] = " ";
+static size_t len_inputFS = 0;
+static char *inputFS = NULL; /* FS at time of input, for field splitting */
#define MAXFLD 2
int nfields = MAXFLD; /* last allocated slot for $i */
@@ -54,8 +57,8 @@ int lastfld = 0; /* last used field */
int argno = 1; /* current input argument number */
extern Awkfloat *ARGC;
-static Cell dollar0 = { OCELL, CFLD, NULL, "", 0.0, REC|STR|DONTFREE };
-static Cell dollar1 = { OCELL, CFLD, NULL, "", 0.0, FLD|STR|DONTFREE };
+static Cell dollar0 = { OCELL, CFLD, NULL, EMPTY, 0.0, REC|STR|DONTFREE };
+static Cell dollar1 = { OCELL, CFLD, NULL, EMPTY, 0.0, FLD|STR|DONTFREE };
void recinit(unsigned int n)
{
@@ -118,9 +121,17 @@ void initgetrec(void)
*/
void savefs(void)
{
- if (strlen(getsval(fsloc)) >= sizeof (inputFS))
+ size_t len;
+ if ((len = strlen(getsval(fsloc))) < len_inputFS) {
+ strlcpy(inputFS, *FS, sizeof(inputFS)); /* for subsequent field splitting */
+ return;
+ }
+
+ len_inputFS = len + 1;
+ inputFS = realloc(inputFS, len_inputFS);
+ if (inputFS == NULL)
FATAL("field separator %.10s... is too long", *FS);
- strlcpy(inputFS, *FS, sizeof(inputFS));
+ memcpy(inputFS, *FS, len_inputFS);
}
static bool firsttime = true;
@@ -335,14 +346,14 @@ void fldbld(void) /* create fields from current record */
*fr = 0;
} else if ((sep = *inputFS) == 0) { /* new: FS="" => 1 char/field */
for (i = 0; *r != '\0'; r += n) {
- char buf[MB_CUR_MAX + 1];
+ char buf[MB_LEN_MAX + 1];
i++;
if (i > nfields)
growfldtab(i);
if (freeable(fldtab[i]))
xfree(fldtab[i]->sval);
- n = mblen(r, MB_CUR_MAX);
+ n = mblen(r, MB_LEN_MAX);
if (n < 0)
n = 1;
memcpy(buf, r, n);
@@ -406,7 +417,7 @@ void cleanfld(int n1, int n2) /* clean out fields n1 .. n2 inclusive */
p = fldtab[i];
if (freeable(p))
xfree(p->sval);
- p->sval = "";
+ p->sval = EMPTY,
p->tval = FLD | STR | DONTFREE;
}
}
diff --git a/usr.bin/awk/main.c b/usr.bin/awk/main.c
index cb23a884667..9c4e47874a9 100644
--- a/usr.bin/awk/main.c
+++ b/usr.bin/awk/main.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: main.c,v 1.35 2020/06/10 21:04:40 millert Exp $ */
+/* $OpenBSD: main.c,v 1.36 2020/06/10 21:05:02 millert Exp $ */
/****************************************************************
Copyright (C) Lucent Technologies 1997
All Rights Reserved
@@ -23,7 +23,7 @@ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.
****************************************************************/
-const char *version = "version 20200105";
+const char *version = "version 20200131";
#define DEBUG
#include <stdio.h>
diff --git a/usr.bin/awk/maketab.c b/usr.bin/awk/maketab.c
index a488d7ed187..6c25233503a 100644
--- a/usr.bin/awk/maketab.c
+++ b/usr.bin/awk/maketab.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: maketab.c,v 1.16 2020/06/10 21:03:36 millert Exp $ */
+/* $OpenBSD: maketab.c,v 1.17 2020/06/10 21:05:02 millert Exp $ */
/****************************************************************
Copyright (C) Lucent Technologies 1997
All Rights Reserved
@@ -123,8 +123,6 @@ int main(int argc, char *argv[])
printf("#include <stdio.h>\n");
printf("#include \"awk.h\"\n");
printf("#include \"ytab.h\"\n\n");
- for (i = SIZE; --i >= 0; )
- names[i] = "";
if (argc != 2) {
fprintf(stderr, "usage: maketab YTAB_H\n");
@@ -161,10 +159,8 @@ int main(int argc, char *argv[])
table[p->token-FIRSTTOKEN] = p->name;
printf("\nCell *(*proctab[%d])(Node **, int) = {\n", SIZE);
for (i=0; i<SIZE; i++)
- if (table[i]==NULL)
- printf("\tnullproc,\t/* %s */\n", names[i]);
- else
- printf("\t%s,\t/* %s */\n", table[i], names[i]);
+ printf("\t%s,\t/* %s */\n",
+ table[i] ? table[i] : "nullproc", names[i] ? names[i] : "");
printf("};\n\n");
printf("const char *tokname(int n)\n"); /* print a tokname() function */
diff --git a/usr.bin/awk/run.c b/usr.bin/awk/run.c
index 605b71e47f6..c4a4254de64 100644
--- a/usr.bin/awk/run.c
+++ b/usr.bin/awk/run.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: run.c,v 1.55 2020/06/10 21:04:40 millert Exp $ */
+/* $OpenBSD: run.c,v 1.56 2020/06/10 21:05:02 millert Exp $ */
/****************************************************************
Copyright (C) Lucent Technologies 1997
All Rights Reserved
@@ -27,6 +27,7 @@ THIS SOFTWARE.
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
+#include <fcntl.h>
#include <setjmp.h>
#include <limits.h>
#include <math.h>
@@ -91,7 +92,7 @@ static Cell exitcell ={ OJUMP, JEXIT, 0, 0, 0.0, NUM, NULL };
Cell *jexit = &exitcell;
static Cell retcell ={ OJUMP, JRET, 0, 0, 0.0, NUM, NULL };
Cell *jret = &retcell;
-static Cell tempcell ={ OCELL, CTEMP, 0, "", 0.0, NUM|STR|DONTFREE, NULL };
+static Cell tempcell ={ OCELL, CTEMP, 0, EMPTY, 0.0, NUM|STR|DONTFREE, NULL };
Node *curnode = NULL; /* the node being executed, for debugging */
@@ -226,7 +227,7 @@ struct Frame *fp = NULL; /* frame pointer. bottom level unused */
Cell *call(Node **a, int n) /* function call. very kludgy and fragile */
{
- static Cell newcopycell = { OCELL, CCOPY, 0, "", 0.0, NUM|STR|DONTFREE, NULL };
+ static Cell newcopycell = { OCELL, CCOPY, 0, EMPTY, 0.0, NUM|STR|DONTFREE, NULL };
int i, ncall, ndef;
int freed = 0; /* handles potential double freeing when fcn & param share a tempcell */
Node *x;
@@ -1254,7 +1255,8 @@ Cell *split(Node **a, int nnn) /* split(a[0], a[1], a[2]); a[3] is type */
{
Cell *x = NULL, *y, *ap;
const char *s, *origs, *t;
- char *fs = NULL, *origfs = NULL;
+ const char *fs = NULL;
+ char *origfs = NULL;
int sep;
char temp, num[50];
int n, tempstat, arg3type;
@@ -1268,7 +1270,7 @@ Cell *split(Node **a, int nnn) /* split(a[0], a[1], a[2]); a[3] is type */
fs = getsval(fsloc);
else if (arg3type == STRING) { /* split(str,arr,"string") */
x = execute(a[2]);
- origfs = fs = strdup(getsval(x));
+ fs = origfs = strdup(getsval(x));
if (fs == NULL)
FATAL("out of space in split");
tempfree(x);
@@ -1820,6 +1822,8 @@ FILE *openfile(int a, const char *us)
files[i].fname = tostring(s);
files[i].fp = fp;
files[i].mode = m;
+ if (fp != stdin && fp != stdout && fp != stderr)
+ (void) fcntl(fileno(fp), F_SETFD, FD_CLOEXEC);
}
return fp;
}
@@ -1845,13 +1849,13 @@ Cell *closefile(Node **a, int n)
for (i = 0; i < nfiles; i++) {
if (files[i].fname && strcmp(x->sval, files[i].fname) == 0) {
if (ferror(files[i].fp))
- WARNING( "i/o error occurred on %s", files[i].fname );
+ FATAL( "i/o error occurred on %s", files[i].fname );
if (files[i].mode == '|' || files[i].mode == LE)
stat = pclose(files[i].fp);
else
stat = fclose(files[i].fp);
if (stat == EOF)
- WARNING( "i/o error occurred closing %s", files[i].fname );
+ FATAL( "i/o error occurred closing %s", files[i].fname );
if (i > 2) /* don't do /dev/std... */
xfree(files[i].fname);
files[i].fname = NULL; /* watch out for ref thru this */
@@ -1871,13 +1875,13 @@ void closeall(void)
for (i = 0; i < FOPEN_MAX; i++) {
if (files[i].fp) {
if (ferror(files[i].fp))
- WARNING( "i/o error occurred on %s", files[i].fname );
+ FATAL( "i/o error occurred on %s", files[i].fname );
if (files[i].mode == '|' || files[i].mode == LE)
stat = pclose(files[i].fp);
else
stat = fclose(files[i].fp);
if (stat == EOF)
- WARNING( "i/o error occurred while closing %s", files[i].fname );
+ FATAL( "i/o error occurred while closing %s", files[i].fname );
}
}
}
@@ -2059,6 +2063,13 @@ void backsub(char **pb_ptr, const char **sptr_ptr) /* handle \\& variations */
{ /* sptr[0] == '\\' */
char *pb = *pb_ptr;
const char *sptr = *sptr_ptr;
+ static bool first = true;
+ static bool do_posix = false;
+
+ if (first) {
+ first = false;
+ do_posix = (getenv("POSIXLY_CORRECT") != NULL);
+ }
if (sptr[1] == '\\') {
if (sptr[2] == '\\' && sptr[3] == '&') { /* \\\& -> \& */
@@ -2068,6 +2079,9 @@ void backsub(char **pb_ptr, const char **sptr_ptr) /* handle \\& variations */
} else if (sptr[2] == '&') { /* \\& -> \ + matched */
*pb++ = '\\';
sptr += 2;
+ } else if (do_posix) { /* \\x -> \x */
+ sptr++;
+ *pb++ = *sptr++;
} else { /* \\x -> \\x */
*pb++ = *sptr++;
*pb++ = *sptr++;
diff --git a/usr.bin/awk/tran.c b/usr.bin/awk/tran.c
index 0318be0c57d..8e8b755f9bb 100644
--- a/usr.bin/awk/tran.c
+++ b/usr.bin/awk/tran.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tran.c,v 1.25 2020/06/10 21:04:40 millert Exp $ */
+/* $OpenBSD: tran.c,v 1.26 2020/06/10 21:05:02 millert Exp $ */
/****************************************************************
Copyright (C) Lucent Technologies 1997
All Rights Reserved
@@ -529,12 +529,14 @@ Cell *catstr(Cell *a, Cell *b) /* concatenate a and b */
if (p == NULL)
FATAL("out of space concatenating %s and %s", sa, sb);
snprintf(p, l, "%s%s", sa, sb);
- char *newbuf = malloc(strlen(p) + 2);
+
+ l++; // add room for ' '
+ char *newbuf = malloc(l);
if (newbuf == NULL)
FATAL("out of space concatenating %s and %s", sa, sb);
// See string() in lex.c; a string "xx" is stored in the symbol
// table as "xx ".
- sprintf(newbuf, "%s ", p);
+ snprintf(newbuf, l, "%s ", p);
c = setsymtab(newbuf, p, 0.0, CON|STR|DONTFREE, symtab);
free(p);
free(newbuf);