aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2021-07-01 17:50:26 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2021-07-01 17:50:26 +0200
commit8b4c429025c233640bd5c5838552f34683a06fc0 (patch)
tree385135c4fd35dbfd8f4e682c3819c0d46dc4770b
parent1573487e2100892d06e3628828690692313a48d5 (diff)
downloadbusybox-w32-8b4c429025c233640bd5c5838552f34683a06fc0.tar.gz
busybox-w32-8b4c429025c233640bd5c5838552f34683a06fc0.tar.bz2
busybox-w32-8b4c429025c233640bd5c5838552f34683a06fc0.zip
awk: use static tmpvars instead of nvalloc(1)ed ones
ptest() was using this idea already. As far as I can see, this is safe. Ttestsuite passes. One downside is that a temporary from e.g. printf invocation won't be freed until the next printf call. function old new delta awk_printf 481 468 -13 as_regex 137 111 -26 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/2 up/down: 0/-39) Total: -39 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--editors/awk.c49
1 files changed, 34 insertions, 15 deletions
diff --git a/editors/awk.c b/editors/awk.c
index 2c2cb74d7..0be044eef 100644
--- a/editors/awk.c
+++ b/editors/awk.c
@@ -559,7 +559,9 @@ struct globals2 {
559 unsigned evaluate__seed; 559 unsigned evaluate__seed;
560 regex_t evaluate__sreg; 560 regex_t evaluate__sreg;
561 561
562 var ptest__v; 562 var ptest__tmpvar;
563 var awk_printf__tmpvar;
564 var as_regex__tmpvar;
563 565
564 tsplitter exec_builtin__tspl; 566 tsplitter exec_builtin__tspl;
565 567
@@ -1775,14 +1777,19 @@ static node *mk_splitter(const char *s, tsplitter *spl)
1775static regex_t *as_regex(node *op, regex_t *preg) 1777static regex_t *as_regex(node *op, regex_t *preg)
1776{ 1778{
1777 int cflags; 1779 int cflags;
1778 var *tmpvar;
1779 const char *s; 1780 const char *s;
1780 1781
1781 if ((op->info & OPCLSMASK) == OC_REGEXP) { 1782 if ((op->info & OPCLSMASK) == OC_REGEXP) {
1782 return icase ? op->r.ire : op->l.re; 1783 return icase ? op->r.ire : op->l.re;
1783 } 1784 }
1784 tmpvar = nvalloc(1); 1785
1785 s = getvar_s(evaluate(op, tmpvar)); 1786#define TMPVAR (&G.as_regex__tmpvar)
1787 //tmpvar = nvalloc(1);
1788 // We use a single "static" tmpvar (instead of on-stack or malloced one)
1789 // to decrease memory consumption in deeply-recursive awk programs.
1790 // The rule to work safely is to never call evaluate() while our static
1791 // TMPVAR's value is still needed.
1792 s = getvar_s(evaluate(op, TMPVAR));
1786 1793
1787 cflags = icase ? REG_EXTENDED | REG_ICASE : REG_EXTENDED; 1794 cflags = icase ? REG_EXTENDED | REG_ICASE : REG_EXTENDED;
1788 /* Testcase where REG_EXTENDED fails (unpaired '{'): 1795 /* Testcase where REG_EXTENDED fails (unpaired '{'):
@@ -1794,7 +1801,8 @@ static regex_t *as_regex(node *op, regex_t *preg)
1794 cflags &= ~REG_EXTENDED; 1801 cflags &= ~REG_EXTENDED;
1795 xregcomp(preg, s, cflags); 1802 xregcomp(preg, s, cflags);
1796 } 1803 }
1797 nvfree(tmpvar, 1); 1804 //nvfree(tmpvar, 1);
1805#undef TMPVAR
1798 return preg; 1806 return preg;
1799} 1807}
1800 1808
@@ -2105,8 +2113,11 @@ static int hashwalk_next(var *v)
2105/* evaluate node, return 1 when result is true, 0 otherwise */ 2113/* evaluate node, return 1 when result is true, 0 otherwise */
2106static int ptest(node *pattern) 2114static int ptest(node *pattern)
2107{ 2115{
2108 /* ptest__v is "static": to save stack space? */ 2116 // We use a single "static" tmpvar (instead of on-stack or malloced one)
2109 return istrue(evaluate(pattern, &G.ptest__v)); 2117 // to decrease memory consumption in deeply-recursive awk programs.
2118 // The rule to work safely is to never call evaluate() while our static
2119 // TMPVAR's value is still needed.
2120 return istrue(evaluate(pattern, &G.ptest__tmpvar));
2110} 2121}
2111 2122
2112/* read next record from stream rsm into a variable v */ 2123/* read next record from stream rsm into a variable v */
@@ -2243,12 +2254,18 @@ static char *awk_printf(node *n, int *len)
2243 const char *s1; 2254 const char *s1;
2244 int i, j, incr, bsize; 2255 int i, j, incr, bsize;
2245 char c, c1; 2256 char c, c1;
2246 var *tmpvar, *arg; 2257 var *arg;
2247 2258
2248 tmpvar = nvalloc(1); 2259 //tmpvar = nvalloc(1);
2249//TODO: above, to avoid allocating a single temporary var, take a pointer 2260#define TMPVAR (&G.awk_printf__tmpvar)
2250//to a temporary that our caller (evaluate()) already has? 2261 // We use a single "static" tmpvar (instead of on-stack or malloced one)
2251 fmt = f = xstrdup(getvar_s(evaluate(nextarg(&n), tmpvar))); 2262 // to decrease memory consumption in deeply-recursive awk programs.
2263 // The rule to work safely is to never call evaluate() while our static
2264 // TMPVAR's value is still needed.
2265 fmt = f = xstrdup(getvar_s(evaluate(nextarg(&n), TMPVAR)));
2266 // ^^^^^^^^^ here we immediately strdup() the value, so the later call
2267 // to evaluate() potentially recursing into another awk_printf() can't
2268 // mangle the value.
2252 2269
2253 i = 0; 2270 i = 0;
2254 while (*f) { 2271 while (*f) {
@@ -2268,7 +2285,7 @@ static char *awk_printf(node *n, int *len)
2268 f++; 2285 f++;
2269 c1 = *f; 2286 c1 = *f;
2270 *f = '\0'; 2287 *f = '\0';
2271 arg = evaluate(nextarg(&n), tmpvar); 2288 arg = evaluate(nextarg(&n), TMPVAR);
2272 2289
2273 j = i; 2290 j = i;
2274 if (c == 'c' || !c) { 2291 if (c == 'c' || !c) {
@@ -2289,7 +2306,9 @@ static char *awk_printf(node *n, int *len)
2289 } 2306 }
2290 2307
2291 free(fmt); 2308 free(fmt);
2292 nvfree(tmpvar, 1); 2309// nvfree(tmpvar, 1);
2310#undef TMPVAR
2311
2293 b = xrealloc(b, i + 1); 2312 b = xrealloc(b, i + 1);
2294 b[i] = '\0'; 2313 b[i] = '\0';
2295#if ENABLE_FEATURE_AWK_GNU_EXTENSIONS 2314#if ENABLE_FEATURE_AWK_GNU_EXTENSIONS