Snap for 10453563 from 21572cbc2b9331989f5ee0b859ce47673c5fde5a to mainline-art-release

Change-Id: I76f2fe4d25f24efe2c09a6d37973bba7ac4ecaae
diff --git a/Android.bp b/Android.bp
index e7d53ac..3f89d6e 100644
--- a/Android.bp
+++ b/Android.bp
@@ -46,7 +46,6 @@
         // in stdio2.h, and this #defines it in awk.h
         "-Wno-macro-redefined",
     ],
-    c_std: "gnu11",
     stl: "none",
     yacc: {
         flags: [
diff --git a/FIXES b/FIXES
index 8e49fe9..53c7841 100644
--- a/FIXES
+++ b/FIXES
@@ -23,7 +23,38 @@
 ****************************************************************/
 
 This file lists all bug fixes, changes, etc., made since the AWK book
-was sent to the printers in August, 1987.
+was sent to the printers in August 1987.
+
+Dec 15, 2022:
+	Force hex escapes in strings to be no more than two characters,
+	as they already are in regular expressions. This brings internal
+	consistency, as well as consistency with gawk. Thanks to
+	Arnold Robbins.
+
+Sep 12, 2022:
+	adjbuf minlen error (cannot be 0) in cat, resulting in NULL pbuf.
+	discovered by todd miller. also use-after-free issue with
+	tempfree in cat, thanks to Miguel Pineiro Jr and valgrind.
+
+Aug 30, 2022:
+	Various leaks and use-after-free issues plugged/fixed.
+	Thanks to Miguel Pineiro Jr. <mpj@pineiro.cc>.
+
+May 23, 2022:
+	Memory leak when assigning a string to some of the built-in
+	variables. allocated string erroneously marked DONTFREE.
+	Thanks to Miguel Pineiro Jr. <mpj@pineiro.cc>.
+
+Mar 14, 2022:
+	Historic bug: command-line "name=value" assignment had been
+	truncating its entry in ARGV. (circa 1989) Thanks to 
+	Miguel Pineiro Jr. <mpj@pineiro.cc>.
+
+Mar 3, 2022:
+	Fixed file management memory leak that appears to have been
+	there since the files array was first initialized with stdin,
+	stdout, and stderr (circa 1992). Thanks to Miguel Pineiro Jr.
+	<mpj@pineiro.cc>.
 
 December 8, 2021:
 	The error handling in closefile and closeall was mangled. Long
@@ -309,7 +340,7 @@
 	#12: Avoid undefined behaviour when using ctype(3) functions in
 	     relex(). Thanks to GitHub user iamleot.
 	#31: Make getline handle numeric strings, and update FIXES. Thanks
-	     to GitHub user arnoldrobbins.
+	     to GitHub user Arnold Robbins (arnoldrobbins)
 	#32: maketab: support build systems with read-only source. Thanks
 	     to GitHub user enh.
 
diff --git a/METADATA b/METADATA
index 052f466..58b7076 100644
--- a/METADATA
+++ b/METADATA
@@ -1,3 +1,7 @@
+# This project was upgraded with external_updater.
+# Usage: tools/external_updater/updater.sh update one-true-awk
+# For more info, check https://cs.android.com/android/platform/superproject/+/master:tools/external_updater/README.md
+
 name: "one-true-awk"
 description: "This is the version of awk described in \'The AWK Programming Language\', by Al Aho, Brian Kernighan, and Peter Weinberger (Addison-Wesley, 1988, ISBN 0-201-07981-X)."
 third_party {
@@ -5,11 +9,11 @@
     type: GIT
     value: "https://github.com/onetrueawk/awk.git"
   }
-  version: "075624a72ab15649f255a3a1dabfd7cb7766a7d7"
+  version: "5e49ea4d1f71d9134734011f2151cae4dbec5e5f"
   license_type: NOTICE
   last_upgrade_date {
     year: 2022
-    month: 3
-    day: 7
+    month: 12
+    day: 16
   }
 }
diff --git a/awk.h b/awk.h
index cc30249..ccd16c9 100644
--- a/awk.h
+++ b/awk.h
@@ -37,7 +37,7 @@
 
 typedef	unsigned char uschar;
 
-#define	xfree(a)	{ if ((a) != NULL) { free((void *)(intptr_t)(a)); (a) = NULL; } }
+#define	xfree(a)	{ free((void *)(intptr_t)(a)); (a) = NULL; }
 /*
  * We sometimes cheat writing read-only pointers to NUL-terminate them
  * and then put back the original value
diff --git a/awkgram.y b/awkgram.y
index 8fc1709..7b2b397 100644
--- a/awkgram.y
+++ b/awkgram.y
@@ -206,9 +206,10 @@
 		{ $$ = op2(AND, notnull($1), notnull($3)); }
 	| ppattern MATCHOP reg_expr	{ $$ = op3($2, NIL, $1, (Node*)makedfa($3, 0)); }
 	| ppattern MATCHOP ppattern
-		{ if (constnode($3))
+		{ if (constnode($3)) {
 			$$ = op3($2, NIL, $1, (Node*)makedfa(strnode($3), 0));
-		  else
+			free($3);
+		  } else
 			$$ = op3($2, (Node *)1, $1, $3); }
 	| ppattern IN varname		{ $$ = op2(INTEST, $1, makearr($3)); }
 	| '(' plist ')' IN varname	{ $$ = op2(INTEST, $2, makearr($5)); }
@@ -233,9 +234,10 @@
 	| pattern NE pattern		{ $$ = op2($2, $1, $3); }
 	| pattern MATCHOP reg_expr	{ $$ = op3($2, NIL, $1, (Node*)makedfa($3, 0)); }
 	| pattern MATCHOP pattern
-		{ if (constnode($3))
+		{ if (constnode($3)) {
 			$$ = op3($2, NIL, $1, (Node*)makedfa(strnode($3), 0));
-		  else
+			free($3);
+		  } else
 			$$ = op3($2, (Node *)1, $1, $3); }
 	| pattern IN varname		{ $$ = op2(INTEST, $1, makearr($3)); }
 	| '(' plist ')' IN varname	{ $$ = op2(INTEST, $2, makearr($5)); }
@@ -388,9 +390,10 @@
 	| MATCHFCN '(' pattern comma reg_expr ')'
 		{ $$ = op3(MATCHFCN, NIL, $3, (Node*)makedfa($5, 1)); }
 	| MATCHFCN '(' pattern comma pattern ')'
-		{ if (constnode($5))
+		{ if (constnode($5)) {
 			$$ = op3(MATCHFCN, NIL, $3, (Node*)makedfa(strnode($5), 1));
-		  else
+			free($5);
+		  } else
 			$$ = op3(MATCHFCN, (Node *)1, $3, $5); }
 	| NUMBER			{ $$ = celltonode($1, CCON); }
 	| SPLIT '(' pattern comma varname comma pattern ')'     /* string */
@@ -404,16 +407,18 @@
 	| subop '(' reg_expr comma pattern ')'
 		{ $$ = op4($1, NIL, (Node*)makedfa($3, 1), $5, rectonode()); }
 	| subop '(' pattern comma pattern ')'
-		{ if (constnode($3))
+		{ if (constnode($3)) {
 			$$ = op4($1, NIL, (Node*)makedfa(strnode($3), 1), $5, rectonode());
-		  else
+			free($3);
+		  } else
 			$$ = op4($1, (Node *)1, $3, $5, rectonode()); }
 	| subop '(' reg_expr comma pattern comma var ')'
 		{ $$ = op4($1, NIL, (Node*)makedfa($3, 1), $5, $7); }
 	| subop '(' pattern comma pattern comma var ')'
-		{ if (constnode($3))
+		{ if (constnode($3)) {
 			$$ = op4($1, NIL, (Node*)makedfa(strnode($3), 1), $5, $7);
-		  else
+			free($3);
+		  } else
 			$$ = op4($1, (Node *)1, $3, $5, $7); }
 	| SUBSTR '(' pattern comma pattern comma pattern ')'
 		{ $$ = op3(SUBSTR, $3, $5, $7); }
diff --git a/lex.c b/lex.c
index 9d1ae06..a5feff4 100644
--- a/lex.c
+++ b/lex.c
@@ -416,19 +416,28 @@
 				break;
 
 			case 'x':	/* hex  \x0-9a-fA-F + */
-			    {	char xbuf[100], *px;
-				for (px = xbuf; (c = input()) != 0 && px-xbuf < 100-2; ) {
-					if (isdigit(c)
-					 || (c >= 'a' && c <= 'f')
-					 || (c >= 'A' && c <= 'F'))
-						*px++ = c;
-					else
+			    {
+				int i;
+
+				n = 0;
+				for (i = 1; i <= 2; i++) {
+					c = input();
+					if (c == 0)
+						break;
+					if (isxdigit(c)) {
+						c = tolower(c);
+						n *= 16;
+						if (isdigit(c))
+							n += (c - '0');
+						else
+							n += 10 + (c - 'a');
+					} else
 						break;
 				}
-				*px = 0;
-				unput(c);
-	  			sscanf(xbuf, "%x", (unsigned int *) &n);
-				*bp++ = n;
+				if (n)
+					*bp++ = n;
+				else
+					unput(c);
 				break;
 			    }
 
@@ -525,7 +534,7 @@
 	char *bp;
 
 	if (buf == NULL && (buf = (char *) malloc(bufsz)) == NULL)
-		FATAL("out of space for rex expr");
+		FATAL("out of space for reg expr");
 	bp = buf;
 	for ( ; (c = input()) != '/' && c != 0; ) {
 		if (!adjbuf(&buf, &bufsz, bp-buf+3, 500, &bp, "regexpr"))
@@ -545,7 +554,7 @@
 	*bp = 0;
 	if (c == 0)
 		SYNTAX("non-terminated regular expression %.10s...", buf);
-	yylval.s = tostring(buf);
+	yylval.s = buf;
 	unput('/');
 	RET(REGEXPR);
 }
diff --git a/lib.c b/lib.c
index c7709f7..ebe296f 100644
--- a/lib.c
+++ b/lib.c
@@ -297,12 +297,13 @@
 
 void setclvar(char *s)	/* set var=value from s */
 {
-	char *p;
+	char *e, *p;
 	Cell *q;
 	double result;
 
 	for (p=s; *p != '='; p++)
 		;
+	e = p;
 	*p++ = 0;
 	p = qstring(p, '\0');
 	q = setsymtab(s, p, 0.0, STR, symtab);
@@ -312,6 +313,8 @@
 		q->tval |= NUM;
 	}
 	DPRINTF("command line set %s to |%s|\n", s, p);
+	free(p);
+	*e = '=';
 }
 
 
diff --git a/main.c b/main.c
index 986f1a3..2ec513c 100644
--- a/main.c
+++ b/main.c
@@ -22,7 +22,7 @@
 THIS SOFTWARE.
 ****************************************************************/
 
-const char	*version = "version 20211208";
+const char	*version = "version 20221215";
 
 #define DEBUG
 #include <stdio.h>
diff --git a/makefile b/makefile
index 9ceaaad..df966ef 100644
--- a/makefile
+++ b/makefile
@@ -36,6 +36,7 @@
 
 # By fiat, to make our lives easier, yacc is now defined to be bison.
 # If you want something else, you're on your own.
+# YACC = yacc -d -b awkgram
 YACC = bison -d
 
 OFILES = b.o main.o parse.o proctab.o tran.o lib.o run.o lex.o
diff --git a/run.c b/run.c
index f5c19a1..483b9d9 100644
--- a/run.c
+++ b/run.c
@@ -971,8 +971,10 @@
 	}
 	*p = '\0';
 	free(fmt);
-	for ( ; a; a = a->nnext)		/* evaluate any remaining args */
-		execute(a);
+	for ( ; a; a = a->nnext) {		/* evaluate any remaining args */
+		x = execute(a);
+		tempfree(x);
+	}
 	*pbuf = buf;
 	*pbufsize = bufsize;
 	return p - buf;
@@ -1195,16 +1197,17 @@
 
 	x = execute(a[0]);
 	n1 = strlen(getsval(x));
-	adjbuf(&s, &ssz, n1, recsize, 0, "cat1");
+	adjbuf(&s, &ssz, n1 + 1, recsize, 0, "cat1");
 	memcpy(s, x->sval, n1);
 
+	tempfree(x);
+
 	y = execute(a[1]);
 	n2 = strlen(getsval(y));
 	adjbuf(&s, &ssz, n1 + n2 + 1, recsize, 0, "cat2");
 	memcpy(s + n1, y->sval, n2);
 	s[n1 + n2] = '\0';
 
-	tempfree(x);
 	tempfree(y);
 
 	z = gettemp();
@@ -1266,6 +1269,7 @@
 
 	y = execute(a[0]);	/* source string */
 	origs = s = strdup(getsval(y));
+	tempfree(y);
 	arg3type = ptoi(a[3]);
 	if (a[2] == NULL)		/* fs string */
 		fs = getsval(fsloc);
@@ -1386,7 +1390,6 @@
 		}
 	}
 	tempfree(ap);
-	tempfree(y);
 	xfree(origs);
 	xfree(origfs);
 	x = gettemp();
@@ -1712,8 +1715,10 @@
 	setfval(x, u);
 	if (nextarg != NULL) {
 		WARNING("warning: function has too many arguments");
-		for ( ; nextarg; nextarg = nextarg->nnext)
-			execute(nextarg);
+		for ( ; nextarg; nextarg = nextarg->nnext) {
+			y = execute(nextarg);
+			tempfree(y);
+		}
 	}
 	return(x);
 }
@@ -1780,13 +1785,13 @@
 	if (files == NULL)
 		FATAL("can't allocate file memory for %zu files", nfiles);
         files[0].fp = stdin;
-	files[0].fname = "/dev/stdin";
+	files[0].fname = tostring("/dev/stdin");
 	files[0].mode = LT;
         files[1].fp = stdout;
-	files[1].fname = "/dev/stdout";
+	files[1].fname = tostring("/dev/stdout");
 	files[1].mode = GT;
         files[2].fp = stderr;
-	files[2].fname = "/dev/stderr";
+	files[2].fname = tostring("/dev/stderr");
 	files[2].mode = GT;
 }
 
@@ -1890,8 +1895,7 @@
 			stat = fclose(files[i].fp) == EOF;
 		if (stat)
 			WARNING("i/o error occurred closing %s", files[i].fname);
-		if (i > 2)	/* don't do /dev/std... */
-			xfree(files[i].fname);
+		xfree(files[i].fname);
 		files[i].fname = NULL;	/* watch out for ref thru this */
 		files[i].fp = NULL;
 		break;
diff --git a/testdir/T.argv b/testdir/T.argv
index b9a67ef..55e2754 100755
--- a/testdir/T.argv
+++ b/testdir/T.argv
@@ -97,6 +97,12 @@
 $awk '{print L $0}' L=11 foo0 L=22 foo0 >foo2
 diff foo1 foo2 || echo 'BAD: T.argv (L=11 L=22)'
 
+echo >foo0
+echo 'name=value
+name=value' >foo1
+$awk 'BEGIN { print ARGV[1] } { print ARGV[1] }' name=value foo0 >foo2
+diff foo1 foo2 || echo 'BAD: T.argv assignment operand modified'
+
 echo 3.345 >foo1
 $awk 'BEGIN { print ARGV[1] + ARGV[2]}' 1 2.345 >foo2
 diff foo1 foo2 || echo 'BAD: T.argv (ARGV[1] + ARGV[2])'
diff --git a/tran.c b/tran.c
index c6ae890..e1496cd 100644
--- a/tran.c
+++ b/tran.c
@@ -70,18 +70,6 @@
 
 extern Cell **fldtab;
 
-static void
-setfree(Cell *vp)
-{
-	if (&vp->sval == FS || &vp->sval == RS ||
-	    &vp->sval == OFS || &vp->sval == ORS ||
-	    &vp->sval == OFMT || &vp->sval == CONVFMT ||
-	    &vp->sval == FILENAME || &vp->sval == SUBSEP)
-		vp->tval |= DONTFREE;
-	else
-		vp->tval &= ~DONTFREE;
-}
-
 void syminit(void)	/* initialize symbol table with builtin vars */
 {
 	literal0 = setsymtab("0", "0", 0.0, NUM|STR|CON|DONTFREE, symtab);
@@ -377,10 +365,9 @@
 	t = s ? tostring(s) : tostring("");	/* in case it's self-assign */
 	if (freeable(vp))
 		xfree(vp->sval);
-	vp->tval &= ~(NUM|CONVC|CONVO);
+	vp->tval &= ~(NUM|DONTFREE|CONVC|CONVO);
 	vp->tval |= STR;
 	vp->fmt = NULL;
-	setfree(vp);
 	DPRINTF("setsval %p: %s = \"%s (%p) \", t=%o r,f=%d,%d\n",
 		(void*)vp, NN(vp->nval), t, (void*)t, vp->tval, donerec, donefld);
 	vp->sval = t;
@@ -576,7 +563,6 @@
 
 char *qstring(const char *is, int delim)	/* collect string up to next delim */
 {
-	const char *os = is;
 	int c, n;
 	const uschar *s = (const uschar *) is;
 	uschar *buf, *bp;
@@ -585,7 +571,7 @@
 		FATAL( "out of space in qstring(%s)", s);
 	for (bp = buf; (c = *s) != delim; s++) {
 		if (c == '\n')
-			SYNTAX( "newline in string %.20s...", os );
+			SYNTAX( "newline in string %.20s...", is );
 		else if (c != '\\')
 			*bp++ = c;
 		else {	/* \something */