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>
This commit is contained in:
parent
182e5a4d00
commit
c72c5552ed
1 changed files with 53 additions and 34 deletions
39
shell/math.c
39
shell/math.c
|
@ -245,7 +245,7 @@ is_right_associative(operator prec)
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
arith_t val;
|
arith_t val;
|
||||||
char *var_name;
|
const char *var_name;
|
||||||
} var_or_num_t;
|
} var_or_num_t;
|
||||||
|
|
||||||
#define VALID_NAME(name) (name)
|
#define VALID_NAME(name) (name)
|
||||||
|
@ -256,15 +256,28 @@ typedef struct remembered_name {
|
||||||
const char *var_name;
|
const char *var_name;
|
||||||
} remembered_name;
|
} remembered_name;
|
||||||
|
|
||||||
|
static ALWAYS_INLINE int isalnum_(int c)
|
||||||
|
{
|
||||||
|
return (isalnum(c) || c == '_');
|
||||||
|
}
|
||||||
|
|
||||||
static arith_t
|
static arith_t
|
||||||
evaluate_string(arith_state_t *math_state, const char *expr);
|
evaluate_string(arith_state_t *math_state, const char *expr);
|
||||||
|
|
||||||
static const char*
|
static const char*
|
||||||
arith_lookup_val(arith_state_t *math_state, var_or_num_t *t)
|
arith_lookup_val(arith_state_t *math_state, var_or_num_t *t)
|
||||||
{
|
{
|
||||||
if (VALID_NAME(t->var_name)) {
|
const char *name = t->var_name;
|
||||||
const char *p = math_state->lookupvar(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) {
|
if (p) {
|
||||||
|
size_t len = e - name;
|
||||||
remembered_name *cur;
|
remembered_name *cur;
|
||||||
remembered_name remember;
|
remembered_name remember;
|
||||||
|
|
||||||
|
@ -272,14 +285,16 @@ arith_lookup_val(arith_state_t *math_state, var_or_num_t *t)
|
||||||
* testcase: a=b; b=a; echo $((a))
|
* testcase: a=b; b=a; echo $((a))
|
||||||
*/
|
*/
|
||||||
for (cur = math_state->list_of_recursed_names; cur; cur = cur->next) {
|
for (cur = math_state->list_of_recursed_names; cur; cur = cur->next) {
|
||||||
if (strcmp(cur->var_name, t->var_name) == 0) {
|
if (strncmp(cur->var_name, name, len) == 0
|
||||||
|
&& !isalnum_(cur->var_name[len])
|
||||||
|
) {
|
||||||
/* yes */
|
/* yes */
|
||||||
return "expression recursion loop detected";
|
return "expression recursion loop detected";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* push current var name */
|
/* push current var name */
|
||||||
remember.var_name = t->var_name;
|
remember.var_name = name;
|
||||||
remember.next = math_state->list_of_recursed_names;
|
remember.next = math_state->list_of_recursed_names;
|
||||||
math_state->list_of_recursed_names = &remember;
|
math_state->list_of_recursed_names = &remember;
|
||||||
|
|
||||||
|
@ -293,7 +308,6 @@ arith_lookup_val(arith_state_t *math_state, var_or_num_t *t)
|
||||||
}
|
}
|
||||||
/* treat undefined var as 0 */
|
/* treat undefined var as 0 */
|
||||||
t->val = 0;
|
t->val = 0;
|
||||||
}
|
|
||||||
return NULL;
|
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 */
|
/* Save to shell variable */
|
||||||
sprintf(buf, ARITH_FMT, rez);
|
sprintf(buf, ARITH_FMT, rez);
|
||||||
|
{
|
||||||
|
char *e = (char*)endofname(top_of_stack->var_name);
|
||||||
|
char c = *e;
|
||||||
|
*e = '\0';
|
||||||
math_state->setvar(top_of_stack->var_name, buf);
|
math_state->setvar(top_of_stack->var_name, buf);
|
||||||
|
*e = c;
|
||||||
|
}
|
||||||
/* After saving, make previous value for v++ or v-- */
|
/* After saving, make previous value for v++ or v-- */
|
||||||
if (op == TOK_POST_INC)
|
if (op == TOK_POST_INC)
|
||||||
rez--;
|
rez--;
|
||||||
|
@ -610,6 +630,7 @@ evaluate_string(arith_state_t *math_state, const char *expr)
|
||||||
* (modulo "09v09v09v09v09v" case,
|
* (modulo "09v09v09v09v09v" case,
|
||||||
* but we have code to detect that early)
|
* 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]));
|
numstackptr = numstack = alloca((expr_len / 2) * sizeof(numstack[0]));
|
||||||
opstackptr = opstack = alloca(expr_len * sizeof(opstack[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) {
|
if (p != expr) {
|
||||||
/* Name */
|
/* Name */
|
||||||
if (!math_state->evaluation_disabled) {
|
if (!math_state->evaluation_disabled) {
|
||||||
size_t var_name_size = (p - expr) + 1; /* +1 for NUL */
|
numstackptr->var_name = expr;
|
||||||
numstackptr->var_name = alloca(var_name_size);
|
dbg("[%d] var:'%.*s'", (int)(numstackptr - numstack), (int)(p - expr), expr);
|
||||||
safe_strncpy(numstackptr->var_name, expr, var_name_size);
|
|
||||||
dbg("[%d] var:'%s'", (int)(numstackptr - numstack), numstackptr->var_name);
|
|
||||||
expr = skip_whitespace(p);
|
expr = skip_whitespace(p);
|
||||||
/* If it is not followed by "=" operator... */
|
/* If it is not followed by "=" operator... */
|
||||||
if (expr[0] != '=' /* not "=..." */
|
if (expr[0] != '=' /* not "=..." */
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue