aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2023-06-18 00:47:55 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2023-06-18 18:12:14 +0200
commitc72c5552edecb8a2f97cd7e2d9a09a3059986cca (patch)
treeeafbd44ec238db465a6eaf95067820f6e7515a09
parent182e5a4d000cdb5808830b1f02c59d40c6e61150 (diff)
downloadbusybox-w32-c72c5552edecb8a2f97cd7e2d9a09a3059986cca.tar.gz
busybox-w32-c72c5552edecb8a2f97cd7e2d9a09a3059986cca.tar.bz2
busybox-w32-c72c5552edecb8a2f97cd7e2d9a09a3059986cca.zip
shell/math: decrease stack usage by not allocating copies of variable names
We risk exhaust stack with alloca() with old code. function old new delta arith_apply 990 1023 +33 evaluate_string 1467 1494 +27 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/0 up/down: 60/0) Total: 60 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--shell/math.c83
1 files changed, 51 insertions, 32 deletions
diff --git a/shell/math.c b/shell/math.c
index f6fed805c..4c1b1b762 100644
--- a/shell/math.c
+++ b/shell/math.c
@@ -245,7 +245,7 @@ is_right_associative(operator prec)
245 245
246typedef struct { 246typedef struct {
247 arith_t val; 247 arith_t val;
248 char *var_name; 248 const char *var_name;
249} var_or_num_t; 249} var_or_num_t;
250 250
251#define VALID_NAME(name) (name) 251#define VALID_NAME(name) (name)
@@ -256,44 +256,58 @@ typedef struct remembered_name {
256 const char *var_name; 256 const char *var_name;
257} remembered_name; 257} remembered_name;
258 258
259static ALWAYS_INLINE int isalnum_(int c)
260{
261 return (isalnum(c) || c == '_');
262}
263
259static arith_t 264static arith_t
260evaluate_string(arith_state_t *math_state, const char *expr); 265evaluate_string(arith_state_t *math_state, const char *expr);
261 266
262static const char* 267static const char*
263arith_lookup_val(arith_state_t *math_state, var_or_num_t *t) 268arith_lookup_val(arith_state_t *math_state, var_or_num_t *t)
264{ 269{
265 if (VALID_NAME(t->var_name)) { 270 const char *name = t->var_name;
266 const char *p = math_state->lookupvar(t->var_name); 271 char c;
267 if (p) { 272 const char *p;
268 remembered_name *cur; 273 char *e = (char*)endofname(name);
269 remembered_name remember; 274
270 275 c = *e;
271 /* did we already see this name? 276 *e = '\0';
272 * testcase: a=b; b=a; echo $((a)) 277 p = math_state->lookupvar(name);
273 */ 278 *e = c;
274 for (cur = math_state->list_of_recursed_names; cur; cur = cur->next) { 279 if (p) {
275 if (strcmp(cur->var_name, t->var_name) == 0) { 280 size_t len = e - name;
276 /* yes */ 281 remembered_name *cur;
277 return "expression recursion loop detected"; 282 remembered_name remember;
278 } 283
284 /* did we already see this name?
285 * testcase: a=b; b=a; echo $((a))
286 */
287 for (cur = math_state->list_of_recursed_names; cur; cur = cur->next) {
288 if (strncmp(cur->var_name, name, len) == 0
289 && !isalnum_(cur->var_name[len])
290 ) {
291 /* yes */
292 return "expression recursion loop detected";
279 } 293 }
294 }
280 295
281 /* push current var name */ 296 /* push current var name */
282 remember.var_name = t->var_name; 297 remember.var_name = name;
283 remember.next = math_state->list_of_recursed_names; 298 remember.next = math_state->list_of_recursed_names;
284 math_state->list_of_recursed_names = &remember; 299 math_state->list_of_recursed_names = &remember;
285 300
286 /* recursively evaluate p as expression */ 301 /* recursively evaluate p as expression */
287 t->val = evaluate_string(math_state, p); 302 t->val = evaluate_string(math_state, p);
288 303
289 /* pop current var name */ 304 /* pop current var name */
290 math_state->list_of_recursed_names = remember.next; 305 math_state->list_of_recursed_names = remember.next;
291 306
292 return math_state->errmsg; 307 return math_state->errmsg;
293 }
294 /* treat undefined var as 0 */
295 t->val = 0;
296 } 308 }
309 /* treat undefined var as 0 */
310 t->val = 0;
297 return NULL; 311 return NULL;
298} 312}
299 313
@@ -447,7 +461,13 @@ arith_apply(arith_state_t *math_state, operator op, var_or_num_t *numstack, var_
447 } 461 }
448 /* Save to shell variable */ 462 /* Save to shell variable */
449 sprintf(buf, ARITH_FMT, rez); 463 sprintf(buf, ARITH_FMT, rez);
450 math_state->setvar(top_of_stack->var_name, buf); 464 {
465 char *e = (char*)endofname(top_of_stack->var_name);
466 char c = *e;
467 *e = '\0';
468 math_state->setvar(top_of_stack->var_name, buf);
469 *e = c;
470 }
451 /* After saving, make previous value for v++ or v-- */ 471 /* After saving, make previous value for v++ or v-- */
452 if (op == TOK_POST_INC) 472 if (op == TOK_POST_INC)
453 rez--; 473 rez--;
@@ -610,6 +630,7 @@ evaluate_string(arith_state_t *math_state, const char *expr)
610 * (modulo "09v09v09v09v09v" case, 630 * (modulo "09v09v09v09v09v" case,
611 * but we have code to detect that early) 631 * but we have code to detect that early)
612 */ 632 */
633 dbg("expr:'%s' expr_len:%u", expr, expr_len);
613 numstackptr = numstack = alloca((expr_len / 2) * sizeof(numstack[0])); 634 numstackptr = numstack = alloca((expr_len / 2) * sizeof(numstack[0]));
614 opstackptr = opstack = alloca(expr_len * sizeof(opstack[0])); 635 opstackptr = opstack = alloca(expr_len * sizeof(opstack[0]));
615 } 636 }
@@ -655,10 +676,8 @@ evaluate_string(arith_state_t *math_state, const char *expr)
655 if (p != expr) { 676 if (p != expr) {
656 /* Name */ 677 /* Name */
657 if (!math_state->evaluation_disabled) { 678 if (!math_state->evaluation_disabled) {
658 size_t var_name_size = (p - expr) + 1; /* +1 for NUL */ 679 numstackptr->var_name = expr;
659 numstackptr->var_name = alloca(var_name_size); 680 dbg("[%d] var:'%.*s'", (int)(numstackptr - numstack), (int)(p - expr), expr);
660 safe_strncpy(numstackptr->var_name, expr, var_name_size);
661 dbg("[%d] var:'%s'", (int)(numstackptr - numstack), numstackptr->var_name);
662 expr = skip_whitespace(p); 681 expr = skip_whitespace(p);
663 /* If it is not followed by "=" operator... */ 682 /* If it is not followed by "=" operator... */
664 if (expr[0] != '=' /* not "=..." */ 683 if (expr[0] != '=' /* not "=..." */