git: 9front

Download patch

ref: 767cceeba3e9dfc47c1633f98f2de833cc12582a
parent: 81dfe1667724b490d6c959f23130ab247f888ac6
author: qwx <qwx@sciops.net>
date: Sun Oct 26 17:59:48 EDT 2025

awk: fix use-after-free in split

when the string passed to split is an element of the array also
passed, e.g.  `split(a[x], a)', we don't want to lose the string value
when reseting the array.  however, the cell is freed during the reset,
and y is now invalid anyway.  instead, detect this case and strdup the
string if needed.  the alternative solution is to always strdup the
string, but this has no practical performance impact even for large
arrays, the intent is clearer and avoids the allocation in all other
cases.

--- a/sys/src/cmd/awk/run.c
+++ b/sys/src/cmd/awk/run.c
@@ -1261,11 +1261,12 @@
 Cell *split(Node **a, int)	/* split(a[0], a[1], a[2]); a[3] is type */
 {
 	Cell *x = 0, *y, *ap;
-	char *s, *t, *fs = 0;
+	char *s, *ds, *t, *fs = 0;
 	char temp, num[50];
 	int n, nb, sep, arg3type;
 
 	y = execute(a[0]);	/* source string */
+	ds = nil;
 	s = getsval(y);
 	arg3type = ptoi(a[3]);
 	if (a[2] == 0)		/* fs string */
@@ -1279,10 +1280,9 @@
 		FATAL("illegal type of split");
 	sep = *fs;
 	ap = execute(a[1]);	/* array name */
-	n = y->tval;
-	y->tval |= DONTFREE;	/* split(a[x], a); */
+	if (isarr(ap) && lookup(y->nval, (Array *)ap->sval) != nil)
+		ds = s = tostring(s);
 	freesymtab(ap);
-	y->tval = n;
 	   dprint( ("split: s=|%s|, a=%s, sep=|%s|\n", s, ap->nval, fs) );
 	ap->tval &= ~STR;
 	ap->tval |= ARR;
@@ -1381,6 +1381,7 @@
 				break;
 		}
 	}
+	free(ds);
 	if (istemp(ap))
 		tfree(ap);
 	if (istemp(y))
--