From 9db344a0f4ed5f6f893940b734215d05e48320e9 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 9 Apr 2018 19:05:11 +0200 Subject: [PATCH] hush: fix var_leaks.tests and var_preserved.tests on NOMMU function old new delta remove_nested_vars - 77 +77 run_pipe 1756 1786 +30 pseudo_exec_argv 376 379 +3 leave_var_nest_level 98 32 -66 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 2/1 up/down: 110/-66) Total: 44 bytes Signed-off-by: Denys Vlasenko --- shell/hush.c | 108 ++++++++++++++++++++++++++++----------------------- 1 file changed, 59 insertions(+), 49 deletions(-) diff --git a/shell/hush.c b/shell/hush.c index 3a4b5d894..885561389 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -2266,6 +2266,7 @@ static int set_local_var(char *str, unsigned flags) } /* Not found or shadowed - create new variable struct */ + debug_printf_env("%s: alloc new var '%s'/%u\n", __func__, str, local_lvl); cur = xzalloc(sizeof(*cur)); cur->var_nest_level = local_lvl; cur->next = *cur_pp; @@ -2420,7 +2421,7 @@ static void set_vars_and_save_old(char **strings) * global linked list. */ } - //bb_error_msg("G.var_nest_level:%d", G.var_nest_level); + debug_printf_env("%s: env override '%s'/%u\n", __func__, *s, G.var_nest_level); set_local_var(*s, (G.var_nest_level << SETFLAG_VARLVL_SHIFT) | SETFLAG_EXPORT); } else if (HUSH_DEBUG) { bb_error_msg_and_die("BUG in varexp4"); @@ -7358,6 +7359,58 @@ static void unset_func(const char *name) } # endif +static void remove_nested_vars(void) +{ + struct variable *cur; + struct variable **cur_pp; + + cur_pp = &G.top_var; + while ((cur = *cur_pp) != NULL) { + if (cur->var_nest_level <= G.var_nest_level) { + cur_pp = &cur->next; + continue; + } + /* Unexport */ + if (cur->flg_export) { + debug_printf_env("unexporting nested '%s'/%u\n", cur->varstr, cur->var_nest_level); + bb_unsetenv(cur->varstr); + } + /* Remove from global list */ + *cur_pp = cur->next; + /* Free */ + if (!cur->max_len) { + debug_printf_env("freeing nested '%s'/%u\n", cur->varstr, cur->var_nest_level); + free(cur->varstr); + } + free(cur); + } +} + +static void enter_var_nest_level(void) +{ + G.var_nest_level++; + debug_printf_env("var_nest_level++ %u\n", G.var_nest_level); + + /* Try: f() { echo -n .; f; }; f + * struct variable::var_nest_level is uint16_t, + * thus limiting recursion to < 2^16. + * In any case, with 8 Mbyte stack SEGV happens + * not too long after 2^16 recursions anyway. + */ + if (G.var_nest_level > 0xff00) + bb_error_msg_and_die("fatal recursion (depth %u)", G.var_nest_level); +} + +static void leave_var_nest_level(void) +{ + G.var_nest_level--; + debug_printf_env("var_nest_level-- %u\n", G.var_nest_level); + if (HUSH_DEBUG && (int)G.var_nest_level < 0) + bb_error_msg_and_die("BUG: nesting underflow"); + + remove_nested_vars(); +} + # if BB_MMU #define exec_function(to_free, funcp, argv) \ exec_function(funcp, argv) @@ -7392,7 +7445,7 @@ static void exec_function(char ***to_free, /* "we are in a function, ok to use return" */ G_flag_return_in_progress = -1; - G.var_nest_level++; + enter_var_nest_level(); IF_HUSH_LOCAL(G.func_nest_level++;) /* On MMU, funcp->body is always non-NULL */ @@ -7412,53 +7465,6 @@ static void exec_function(char ***to_free, # endif } -static void enter_var_nest_level(void) -{ - G.var_nest_level++; - debug_printf_env("var_nest_level++ %u\n", G.var_nest_level); - - /* Try: f() { echo -n .; f; }; f - * struct variable::var_nest_level is uint16_t, - * thus limiting recursion to < 2^16. - * In any case, with 8 Mbyte stack SEGV happens - * not too long after 2^16 recursions anyway. - */ - if (G.var_nest_level > 0xff00) - bb_error_msg_and_die("fatal recursion (depth %u)", G.var_nest_level); -} - -static void leave_var_nest_level(void) -{ - struct variable *cur; - struct variable **cur_pp; - - cur_pp = &G.top_var; - while ((cur = *cur_pp) != NULL) { - if (cur->var_nest_level < G.var_nest_level) { - cur_pp = &cur->next; - continue; - } - /* Unexport */ - if (cur->flg_export) { - debug_printf_env("unexporting nested '%s'/%u\n", cur->varstr, cur->var_nest_level); - bb_unsetenv(cur->varstr); - } - /* Remove from global list */ - *cur_pp = cur->next; - /* Free */ - if (!cur->max_len) { - debug_printf_env("freeing nested '%s'/%u\n", cur->varstr, cur->var_nest_level); - free(cur->varstr); - } - free(cur); - } - - G.var_nest_level--; - debug_printf_env("var_nest_level-- %u\n", G.var_nest_level); - if (HUSH_DEBUG && (int)G.var_nest_level < 0) - bb_error_msg_and_die("BUG: nesting underflow"); -} - static int run_function(const struct function *funcp, char **argv) { int rc; @@ -7648,6 +7654,7 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save, G.shadowed_vars_pp = NULL; /* "don't save, free them instead" */ #else G.shadowed_vars_pp = &nommu_save->old_vars; + G.var_nest_level++; #endif set_vars_and_save_old(new_env); G.shadowed_vars_pp = sv_shadowed; @@ -8522,6 +8529,7 @@ static NOINLINE int run_pipe(struct pipe *pi) while (cmd_no < pi->num_cmds) { struct fd_pair pipefds; #if !BB_MMU + int sv_var_nest_level = G.var_nest_level; volatile nommu_save_t nommu_save; nommu_save.old_vars = NULL; nommu_save.argv = NULL; @@ -8615,6 +8623,8 @@ static NOINLINE int run_pipe(struct pipe *pi) /* Clean up after vforked child */ free(nommu_save.argv); free(nommu_save.argv_from_re_execing); + G.var_nest_level = sv_var_nest_level; + remove_nested_vars(); add_vars(nommu_save.old_vars); #endif free(argv_expanded);