[git commit] hush: fix var_leaks.tests and var_preserved.tests on NOMMU

Denys Vlasenko vda.linux at googlemail.com
Mon Apr 9 17:05:11 UTC 2018


commit: https://git.busybox.net/busybox/commit/?id=9db344a0f4ed5f6f893940b734215d05e48320e9
branch: https://git.busybox.net/busybox/commit/?id=refs/heads/master

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 at googlemail.com>
---
 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);


More information about the busybox-cvs mailing list