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 <vda.linux@googlemail.com>
This commit is contained in:
108
shell/hush.c
108
shell/hush.c
@@ -2266,6 +2266,7 @@ static int set_local_var(char *str, unsigned flags)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Not found or shadowed - create new variable struct */
|
/* 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 = xzalloc(sizeof(*cur));
|
||||||
cur->var_nest_level = local_lvl;
|
cur->var_nest_level = local_lvl;
|
||||||
cur->next = *cur_pp;
|
cur->next = *cur_pp;
|
||||||
@@ -2420,7 +2421,7 @@ static void set_vars_and_save_old(char **strings)
|
|||||||
* global linked list.
|
* 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);
|
set_local_var(*s, (G.var_nest_level << SETFLAG_VARLVL_SHIFT) | SETFLAG_EXPORT);
|
||||||
} else if (HUSH_DEBUG) {
|
} else if (HUSH_DEBUG) {
|
||||||
bb_error_msg_and_die("BUG in varexp4");
|
bb_error_msg_and_die("BUG in varexp4");
|
||||||
@@ -7358,6 +7359,58 @@ static void unset_func(const char *name)
|
|||||||
}
|
}
|
||||||
# endif
|
# 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
|
# if BB_MMU
|
||||||
#define exec_function(to_free, funcp, argv) \
|
#define exec_function(to_free, funcp, argv) \
|
||||||
exec_function(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" */
|
/* "we are in a function, ok to use return" */
|
||||||
G_flag_return_in_progress = -1;
|
G_flag_return_in_progress = -1;
|
||||||
G.var_nest_level++;
|
enter_var_nest_level();
|
||||||
IF_HUSH_LOCAL(G.func_nest_level++;)
|
IF_HUSH_LOCAL(G.func_nest_level++;)
|
||||||
|
|
||||||
/* On MMU, funcp->body is always non-NULL */
|
/* On MMU, funcp->body is always non-NULL */
|
||||||
@@ -7412,53 +7465,6 @@ static void exec_function(char ***to_free,
|
|||||||
# endif
|
# 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)
|
static int run_function(const struct function *funcp, char **argv)
|
||||||
{
|
{
|
||||||
int rc;
|
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" */
|
G.shadowed_vars_pp = NULL; /* "don't save, free them instead" */
|
||||||
#else
|
#else
|
||||||
G.shadowed_vars_pp = &nommu_save->old_vars;
|
G.shadowed_vars_pp = &nommu_save->old_vars;
|
||||||
|
G.var_nest_level++;
|
||||||
#endif
|
#endif
|
||||||
set_vars_and_save_old(new_env);
|
set_vars_and_save_old(new_env);
|
||||||
G.shadowed_vars_pp = sv_shadowed;
|
G.shadowed_vars_pp = sv_shadowed;
|
||||||
@@ -8522,6 +8529,7 @@ static NOINLINE int run_pipe(struct pipe *pi)
|
|||||||
while (cmd_no < pi->num_cmds) {
|
while (cmd_no < pi->num_cmds) {
|
||||||
struct fd_pair pipefds;
|
struct fd_pair pipefds;
|
||||||
#if !BB_MMU
|
#if !BB_MMU
|
||||||
|
int sv_var_nest_level = G.var_nest_level;
|
||||||
volatile nommu_save_t nommu_save;
|
volatile nommu_save_t nommu_save;
|
||||||
nommu_save.old_vars = NULL;
|
nommu_save.old_vars = NULL;
|
||||||
nommu_save.argv = NULL;
|
nommu_save.argv = NULL;
|
||||||
@@ -8615,6 +8623,8 @@ static NOINLINE int run_pipe(struct pipe *pi)
|
|||||||
/* Clean up after vforked child */
|
/* Clean up after vforked child */
|
||||||
free(nommu_save.argv);
|
free(nommu_save.argv);
|
||||||
free(nommu_save.argv_from_re_execing);
|
free(nommu_save.argv_from_re_execing);
|
||||||
|
G.var_nest_level = sv_var_nest_level;
|
||||||
|
remove_nested_vars();
|
||||||
add_vars(nommu_save.old_vars);
|
add_vars(nommu_save.old_vars);
|
||||||
#endif
|
#endif
|
||||||
free(argv_expanded);
|
free(argv_expanded);
|
||||||
|
Reference in New Issue
Block a user