ref: b30c2cae2ee8c2c7cd27ecdead8fb71730497ab5
parent: f6f3e05cf56fab3261d49b0bb26f2dbdd0aa7188
author: qwx <qwx@sciops.net>
date: Mon Nov 3 04:08:20 EST 2025
add awk-recache: fix use after free in re caching (pending)
--- /dev/null
+++ b/awk-recache
@@ -1,0 +1,129 @@
+diff f3ac883d0db6842870cdabd44ed938b92de87d71 uncommitted
+--- a/sys/src/cmd/awk/lib.c
++++ b/sys/src/cmd/awk/lib.c
+@@ -429,7 +429,8 @@
+ break;
+ }
+ }
+- return i;
++ releasere(p);
++ return i;
+ }
+
+ void recbld(void) /* create $0 from $1..$NF if necessary */
+--- a/sys/src/cmd/awk/proto.h
++++ b/sys/src/cmd/awk/proto.h
+@@ -35,6 +35,7 @@
+ extern void unput(int);
+ extern void unputstr(char *);
+
++extern void releasere(void *);
+ extern void *compre(char *);
+ extern int hexstr(char **);
+ extern void quoted(char **, char **, char *);
+--- a/sys/src/cmd/awk/re.c
++++ b/sys/src/cmd/awk/re.c
+@@ -64,11 +64,24 @@
+ {+ char *re;
+ int use;
++ int inuse;
+ Reprog *program;
+ } pattern[NPATS];
+
+ static int npats; /* cache fill level */
+
++void
++releasere(void *p)
++{++ int i;
++
++ for (i = 0; i < npats; i++)
++ if (pattern[i].program == p) {++ pattern[i].inuse--;
++ break;
++ }
++}
++
+ /* Compile a pattern */
+ void
+ *compre(char *pat)
+@@ -81,6 +94,7 @@
+ for (i = 0; i < npats; i++)
+ if (!strcmp(pat, pattern[i].re)) {+ pattern[i].use++;
++ pattern[i].inuse++;
+ return((void *) pattern[i].program);
+ }
+ }
+@@ -162,20 +176,25 @@
+ if (npats < NPATS) /* Room in cache */
+ i = npats++;
+ else { /* Throw out least used */+- int use = pattern[0].use;
+- i = 0;
+- for (j = 1; j < NPATS; j++) {+- if (pattern[j].use < use) {++ int use = -1U;
++ i = -1;
++ for (j = 0; j < NPATS; j++) {++ if (pattern[j].inuse == 0 && pattern[j].use < use) {+ use = pattern[j].use;
+ i = j;
+ }
+ }
+- xfree(pattern[i].program);
+- xfree(pattern[i].re);
++ if (i >= 0) {++ xfree(pattern[i].program);
++ xfree(pattern[i].re);
++ }
+ }
+- pattern[i].re = tostring(pat);
+- pattern[i].program = program;
+- pattern[i].use = 1;
++ if (i >= 0) {++ pattern[i].re = tostring(pat);
++ pattern[i].program = program;
++ pattern[i].use = 1;
++ pattern[i].inuse = 1;
++ }
+ }
+ return((void *) program);
+ }
+--- a/sys/src/cmd/awk/run.c
++++ b/sys/src/cmd/awk/run.c
+@@ -608,6 +608,7 @@
+ i = pmatch(p, s, s);
+ else
+ i = match(p, s, s);
++ releasere(p);
+ if (istemp(x))
+ tfree(x);
+ if (n == MATCHFCN) {+@@ -1324,8 +1325,7 @@
+ else
+ setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
+ spdone:
+- p = nil;
+- USED(p);
++ releasere(p);
+ } else if (sep == ' ') {+ for (n = 0; ; ) {+ while (*s == ' ' || *s == '\t' || *s == '\n')
+@@ -1884,6 +1884,7 @@
+ setsval(x, buf); /* BUG: should be able to avoid copy */
+ result = True;;
+ }
++ releasere(p);
+ if (istemp(x))
+ tfree(x);
+ if (istemp(y))
+@@ -1981,6 +1982,7 @@
+ ;
+ setsval(x, buf); /* BUG: should be able to avoid copy + free */
+ }
++ releasere(p);
+ if (istemp(x))
+ tfree(x);
+ if (istemp(y))
--
⑨