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))
--
⑨