Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.busybox.net/busybox.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2023-06-18 01:47:55 +0300
committerDenys Vlasenko <vda.linux@googlemail.com>2023-06-18 19:12:14 +0300
commitc72c5552edecb8a2f97cd7e2d9a09a3059986cca (patch)
treeeafbd44ec238db465a6eaf95067820f6e7515a09
parent182e5a4d000cdb5808830b1f02c59d40c6e61150 (diff)
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)
typedef struct {
arith_t val;
- char *var_name;
+ const char *var_name;
} var_or_num_t;
#define VALID_NAME(name) (name)
@@ -256,44 +256,58 @@ typedef struct remembered_name {
const char *var_name;
} remembered_name;
+static ALWAYS_INLINE int isalnum_(int c)
+{
+ return (isalnum(c) || c == '_');
+}
+
static arith_t
evaluate_string(arith_state_t *math_state, const char *expr);
static const char*
arith_lookup_val(arith_state_t *math_state, var_or_num_t *t)
{
- if (VALID_NAME(t->var_name)) {
- const char *p = math_state->lookupvar(t->var_name);
- if (p) {
- remembered_name *cur;
- remembered_name remember;
-
- /* did we already see this name?
- * testcase: a=b; b=a; echo $((a))
- */
- for (cur = math_state->list_of_recursed_names; cur; cur = cur->next) {
- if (strcmp(cur->var_name, t->var_name) == 0) {
- /* yes */
- return "expression recursion loop detected";
- }
+ const char *name = t->var_name;
+ char c;
+ const char *p;
+ char *e = (char*)endofname(name);
+
+ c = *e;
+ *e = '\0';
+ p = math_state->lookupvar(name);
+ *e = c;
+ if (p) {
+ size_t len = e - name;
+ remembered_name *cur;
+ remembered_name remember;
+
+ /* did we already see this name?
+ * testcase: a=b; b=a; echo $((a))
+ */
+ for (cur = math_state->list_of_recursed_names; cur; cur = cur->next) {
+ if (strncmp(cur->var_name, name, len) == 0
+ && !isalnum_(cur->var_name[len])
+ ) {
+ /* yes */
+ return "expression recursion loop detected";
}
+ }
- /* push current var name */
- remember.var_name = t->var_name;
- remember.next = math_state->list_of_recursed_names;
- math_state->list_of_recursed_names = &remember;
+ /* push current var name */
+ remember.var_name = name;
+ remember.next = math_state->list_of_recursed_names;
+ math_state->list_of_recursed_names = &remember;
- /* recursively evaluate p as expression */
- t->val = evaluate_string(math_state, p);
+ /* recursively evaluate p as expression */
+ t->val = evaluate_string(math_state, p);
- /* pop current var name */
- math_state->list_of_recursed_names = remember.next;
+ /* pop current var name */
+ math_state->list_of_recursed_names = remember.next;
- return math_state->errmsg;
- }
- /* treat undefined var as 0 */
- t->val = 0;
+ return math_state->errmsg;
}
+ /* treat undefined var as 0 */
+ t->val = 0;
return NULL;
}
@@ -447,7 +461,13 @@ arith_apply(arith_state_t *math_state, operator op, var_or_num_t *numstack, var_
}
/* Save to shell variable */
sprintf(buf, ARITH_FMT, rez);
- math_state->setvar(top_of_stack->var_name, buf);
+ {
+ char *e = (char*)endofname(top_of_stack->var_name);
+ char c = *e;
+ *e = '\0';
+ math_state->setvar(top_of_stack->var_name, buf);
+ *e = c;
+ }
/* After saving, make previous value for v++ or v-- */
if (op == TOK_POST_INC)
rez--;
@@ -610,6 +630,7 @@ evaluate_string(arith_state_t *math_state, const char *expr)
* (modulo "09v09v09v09v09v" case,
* but we have code to detect that early)
*/
+ dbg("expr:'%s' expr_len:%u", expr, expr_len);
numstackptr = numstack = alloca((expr_len / 2) * sizeof(numstack[0]));
opstackptr = opstack = alloca(expr_len * sizeof(opstack[0]));
}
@@ -655,10 +676,8 @@ evaluate_string(arith_state_t *math_state, const char *expr)
if (p != expr) {
/* Name */
if (!math_state->evaluation_disabled) {
- size_t var_name_size = (p - expr) + 1; /* +1 for NUL */
- numstackptr->var_name = alloca(var_name_size);
- safe_strncpy(numstackptr->var_name, expr, var_name_size);
- dbg("[%d] var:'%s'", (int)(numstackptr - numstack), numstackptr->var_name);
+ numstackptr->var_name = expr;
+ dbg("[%d] var:'%.*s'", (int)(numstackptr - numstack), (int)(p - expr), expr);
expr = skip_whitespace(p);
/* If it is not followed by "=" operator... */
if (expr[0] != '=' /* not "=..." */