shithub: kwa

Download patch

ref: 681f270acd130d2c0d6aa78e1caf9dc3a1fcc3fb
parent: 11e0cd792213373300d37a6a7ad3157f28416299
author: qwx <qwx@sciops.net>
date: Sun Oct 26 18:00:39 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.
revealed by crash in t.split2a.

--- a/run.c
+++ b/run.c
@@ -1238,12 +1238,13 @@
 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];
 	Awkfloat f;
 	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 */
@@ -1257,10 +1258,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;
@@ -1359,6 +1359,7 @@
 				break;
 		}
 	}
+	free(ds);
 	if (istemp(ap))
 		tfree(ap);
 	if (istemp(y))
--