aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2018-04-09 19:05:11 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2018-04-09 19:05:11 +0200
commit9db344a0f4ed5f6f893940b734215d05e48320e9 (patch)
treeda03d9e54ffafbc22c3d4c795c82e872290fbc63
parenteb0de05d682b28fcf7465358ea31cf8574c1221b (diff)
downloadbusybox-9db344a0f4ed5f6f893940b734215d05e48320e9.tar.gz
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>
-rw-r--r--shell/hush.c108
1 files 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);