[git commit] hush: implement "return NUM in trap sets $? after trap"

Denys Vlasenko vda.linux at googlemail.com
Thu Feb 20 15:37:59 UTC 2020


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

function                                             old     new   delta
builtin_return                                        47      67     +20
check_and_run_traps                                  243     259     +16
run_pipe                                            1583    1597     +14
hush_main                                           1076    1086     +10
run_list                                            1054    1055      +1
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 5/0 up/down: 61/0)               Total: 61 bytes

Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 shell/ash_test/ash-misc/exitcode_trap3.right   |  2 ++
 shell/ash_test/ash-misc/exitcode_trap3.tests   |  9 ++++++++
 shell/ash_test/ash-misc/exitcode_trap4.right   |  2 ++
 shell/ash_test/ash-misc/exitcode_trap4.tests   |  8 +++++++
 shell/ash_test/ash-misc/exitcode_trap5.right   |  3 +++
 shell/ash_test/ash-misc/exitcode_trap5.tests   | 10 +++++++++
 shell/hush.c                                   | 31 +++++++++++++++++++++++++-
 shell/hush_test/hush-misc/exitcode_trap3.right |  2 ++
 shell/hush_test/hush-misc/exitcode_trap3.tests |  9 ++++++++
 shell/hush_test/hush-misc/exitcode_trap4.right |  2 ++
 shell/hush_test/hush-misc/exitcode_trap4.tests |  8 +++++++
 shell/hush_test/hush-misc/exitcode_trap5.right |  3 +++
 shell/hush_test/hush-misc/exitcode_trap5.tests | 10 +++++++++
 13 files changed, 98 insertions(+), 1 deletion(-)

diff --git a/shell/ash_test/ash-misc/exitcode_trap3.right b/shell/ash_test/ash-misc/exitcode_trap3.right
new file mode 100644
index 000000000..f275cdc45
--- /dev/null
+++ b/shell/ash_test/ash-misc/exitcode_trap3.right
@@ -0,0 +1,2 @@
+TERM
+42:42
diff --git a/shell/ash_test/ash-misc/exitcode_trap3.tests b/shell/ash_test/ash-misc/exitcode_trap3.tests
new file mode 100755
index 000000000..98745e463
--- /dev/null
+++ b/shell/ash_test/ash-misc/exitcode_trap3.tests
@@ -0,0 +1,9 @@
+# "return" in trap should not use last command's exitcode,
+# but exitcode on entering the trap.
+trap "echo TERM;return" term
+f() {
+	(sleep 1; kill $$) &
+	until (exit 42) do (exit 42); done
+}
+f
+echo 42:$?
diff --git a/shell/ash_test/ash-misc/exitcode_trap4.right b/shell/ash_test/ash-misc/exitcode_trap4.right
new file mode 100644
index 000000000..ed6989593
--- /dev/null
+++ b/shell/ash_test/ash-misc/exitcode_trap4.right
@@ -0,0 +1,2 @@
+TERM
+11:11
diff --git a/shell/ash_test/ash-misc/exitcode_trap4.tests b/shell/ash_test/ash-misc/exitcode_trap4.tests
new file mode 100755
index 000000000..36dba90bd
--- /dev/null
+++ b/shell/ash_test/ash-misc/exitcode_trap4.tests
@@ -0,0 +1,8 @@
+# "return" in trap sets $? after trap
+trap "echo TERM;return 11" term
+f() {
+	(sleep 1; kill $$) &
+	until (exit 42) do (exit 42); done
+}
+f
+echo 11:$?
diff --git a/shell/ash_test/ash-misc/exitcode_trap5.right b/shell/ash_test/ash-misc/exitcode_trap5.right
new file mode 100644
index 000000000..1ad4443b4
--- /dev/null
+++ b/shell/ash_test/ash-misc/exitcode_trap5.right
@@ -0,0 +1,3 @@
+TERM
+Nested
+Zero:0
diff --git a/shell/ash_test/ash-misc/exitcode_trap5.tests b/shell/ash_test/ash-misc/exitcode_trap5.tests
new file mode 100755
index 000000000..332a06463
--- /dev/null
+++ b/shell/ash_test/ash-misc/exitcode_trap5.tests
@@ -0,0 +1,10 @@
+# "return" in trap sets $? after trap...
+# ...but not a nested one!
+g() { echo Nested; return 22; }
+trap "echo TERM;false;g" term
+f() {
+	(kill $$) &
+	sleep 1
+}
+f
+echo Zero:$?
diff --git a/shell/hush.c b/shell/hush.c
index bced388bf..6172f2285 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -988,6 +988,9 @@ struct globals {
 # define G_fatal_sig_mask 0
 #endif
 #if ENABLE_HUSH_TRAP
+# if ENABLE_HUSH_FUNCTIONS
+	int return_exitcode;
+# endif
 	char **traps; /* char *traps[NSIG] */
 # define G_traps G.traps
 #else
@@ -2097,6 +2100,7 @@ static int check_and_run_traps(void)
 		} while (sig < NSIG);
 		break;
  got_sig:
+#if ENABLE_HUSH_TRAP
 		if (G_traps && G_traps[sig]) {
 			debug_printf_exec("%s: sig:%d handler:'%s'\n", __func__, sig, G.traps[sig]);
 			if (G_traps[sig][0]) {
@@ -2110,12 +2114,18 @@ static int check_and_run_traps(void)
 				save_rcode = G.last_exitcode;
 				builtin_eval(argv);
 				free(argv[1]);
-//FIXME: shouldn't it be set to 128 + sig instead?
 				G.last_exitcode = save_rcode;
+# if ENABLE_HUSH_FUNCTIONS
+				if (G.return_exitcode >= 0) {
+					debug_printf_exec("trap exitcode:%d\n", G.return_exitcode);
+					G.last_exitcode = G.return_exitcode;
+				}
+# endif
 				last_sig = sig;
 			} /* else: "" trap, ignoring signal */
 			continue;
 		}
+#endif
 		/* not a trap: special action */
 		switch (sig) {
 		case SIGINT:
@@ -8127,6 +8137,10 @@ static int run_function(const struct function *funcp, char **argv)
 	IF_HUSH_LOCAL(leave_var_nest_level();)
 
 	G_flag_return_in_progress = sv_flg;
+# if ENABLE_HUSH_TRAP
+	debug_printf_exec("G.return_exitcode=-1\n");
+	G.return_exitcode = -1; /* invalidate stashed return value */
+# endif
 
 	restore_G_args(&sv, argv);
 
@@ -9628,6 +9642,9 @@ static int run_list(struct pipe *pi)
 			debug_printf_exec(": builtin/func exitcode %d\n", rcode);
 			G.last_exitcode = rcode;
 			check_and_run_traps();
+#if ENABLE_HUSH_TRAP && ENABLE_HUSH_FUNCTIONS
+			rcode = G.last_exitcode; /* "return" in trap can change it, read back */
+#endif
 #if ENABLE_HUSH_LOOPS
 			/* Was it "break" or "continue"? */
 			if (G.flag_break_continue) {
@@ -9684,6 +9701,9 @@ static int run_list(struct pipe *pi)
  check_traps:
 			G.last_exitcode = rcode;
 			check_and_run_traps();
+#if ENABLE_HUSH_TRAP && ENABLE_HUSH_FUNCTIONS
+			rcode = G.last_exitcode; /* "return" in trap can change it, read back */
+#endif
 		}
 
 		/* Handle "set -e" */
@@ -9907,6 +9927,9 @@ int hush_main(int argc, char **argv)
 	INIT_G();
 	if (EXIT_SUCCESS != 0) /* if EXIT_SUCCESS == 0, it is already done */
 		G.last_exitcode = EXIT_SUCCESS;
+#if ENABLE_HUSH_TRAP && ENABLE_HUSH_FUNCTIONS
+	G.return_exitcode = -1;
+#endif
 
 #if ENABLE_HUSH_FAST
 	G.count_SIGCHLD++; /* ensure it is != G.handled_SIGCHLD */
@@ -11745,6 +11768,12 @@ static int FAST_FUNC builtin_return(char **argv)
 	 * 255  <== we also do this
 	 */
 	rc = parse_numeric_argv1(argv, G.last_exitcode, 0);
+# if ENABLE_HUSH_TRAP
+	if (argv[1]) { /* "return ARG" inside a running trap sets $? */
+		debug_printf_exec("G.return_exitcode=%d\n", rc);
+		G.return_exitcode = rc;
+	}
+# endif
 	return rc;
 }
 #endif
diff --git a/shell/hush_test/hush-misc/exitcode_trap3.right b/shell/hush_test/hush-misc/exitcode_trap3.right
new file mode 100644
index 000000000..f275cdc45
--- /dev/null
+++ b/shell/hush_test/hush-misc/exitcode_trap3.right
@@ -0,0 +1,2 @@
+TERM
+42:42
diff --git a/shell/hush_test/hush-misc/exitcode_trap3.tests b/shell/hush_test/hush-misc/exitcode_trap3.tests
new file mode 100755
index 000000000..98745e463
--- /dev/null
+++ b/shell/hush_test/hush-misc/exitcode_trap3.tests
@@ -0,0 +1,9 @@
+# "return" in trap should not use last command's exitcode,
+# but exitcode on entering the trap.
+trap "echo TERM;return" term
+f() {
+	(sleep 1; kill $$) &
+	until (exit 42) do (exit 42); done
+}
+f
+echo 42:$?
diff --git a/shell/hush_test/hush-misc/exitcode_trap4.right b/shell/hush_test/hush-misc/exitcode_trap4.right
new file mode 100644
index 000000000..ed6989593
--- /dev/null
+++ b/shell/hush_test/hush-misc/exitcode_trap4.right
@@ -0,0 +1,2 @@
+TERM
+11:11
diff --git a/shell/hush_test/hush-misc/exitcode_trap4.tests b/shell/hush_test/hush-misc/exitcode_trap4.tests
new file mode 100755
index 000000000..36dba90bd
--- /dev/null
+++ b/shell/hush_test/hush-misc/exitcode_trap4.tests
@@ -0,0 +1,8 @@
+# "return" in trap sets $? after trap
+trap "echo TERM;return 11" term
+f() {
+	(sleep 1; kill $$) &
+	until (exit 42) do (exit 42); done
+}
+f
+echo 11:$?
diff --git a/shell/hush_test/hush-misc/exitcode_trap5.right b/shell/hush_test/hush-misc/exitcode_trap5.right
new file mode 100644
index 000000000..1ad4443b4
--- /dev/null
+++ b/shell/hush_test/hush-misc/exitcode_trap5.right
@@ -0,0 +1,3 @@
+TERM
+Nested
+Zero:0
diff --git a/shell/hush_test/hush-misc/exitcode_trap5.tests b/shell/hush_test/hush-misc/exitcode_trap5.tests
new file mode 100755
index 000000000..332a06463
--- /dev/null
+++ b/shell/hush_test/hush-misc/exitcode_trap5.tests
@@ -0,0 +1,10 @@
+# "return" in trap sets $? after trap...
+# ...but not a nested one!
+g() { echo Nested; return 22; }
+trap "echo TERM;false;g" term
+f() {
+	(kill $$) &
+	sleep 1
+}
+f
+echo Zero:$?


More information about the busybox-cvs mailing list