aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2016-10-01 22:28:03 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2016-10-01 22:28:03 +0200
commit04b46bced991f802a17c0fc43c8f8448e4eb2c8f (patch)
treefa9f4f151950d21aca3bbf9a3c4bfa01853976cc
parent0dd8e45d42a420a570e7cada80a5fb1ef2052054 (diff)
downloadbusybox-w32-04b46bced991f802a17c0fc43c8f8448e4eb2c8f.tar.gz
busybox-w32-04b46bced991f802a17c0fc43c8f8448e4eb2c8f.tar.bz2
busybox-w32-04b46bced991f802a17c0fc43c8f8448e4eb2c8f.zip
hush: 'return' should have effect earlier
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--shell/hush.c34
-rw-r--r--shell/hush_test/hush-trap/return_in_trap1.right4
-rwxr-xr-xshell/hush_test/hush-trap/return_in_trap1.tests18
3 files changed, 42 insertions, 14 deletions
diff --git a/shell/hush.c b/shell/hush.c
index 3c4621f67..8693d7562 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -777,6 +777,9 @@ struct globals {
777 * 1: return is invoked, skip all till end of func 777 * 1: return is invoked, skip all till end of func
778 */ 778 */
779 smallint flag_return_in_progress; 779 smallint flag_return_in_progress;
780# define G_flag_return_in_progress (G.flag_return_in_progress)
781#else
782# define G_flag_return_in_progress 0
780#endif 783#endif
781 smallint exiting; /* used to prevent EXIT trap recursion */ 784 smallint exiting; /* used to prevent EXIT trap recursion */
782 /* These four support $?, $#, and $1 */ 785 /* These four support $?, $#, and $1 */
@@ -1736,6 +1739,7 @@ static int check_and_run_traps(void)
1736 break; 1739 break;
1737 got_sig: 1740 got_sig:
1738 if (G.traps && G.traps[sig]) { 1741 if (G.traps && G.traps[sig]) {
1742 debug_printf_exec("%s: sig:%d handler:'%s'\n", __func__, sig, G.traps[sig]);
1739 if (G.traps[sig][0]) { 1743 if (G.traps[sig][0]) {
1740 /* We have user-defined handler */ 1744 /* We have user-defined handler */
1741 smalluint save_rcode; 1745 smalluint save_rcode;
@@ -1753,6 +1757,7 @@ static int check_and_run_traps(void)
1753 /* not a trap: special action */ 1757 /* not a trap: special action */
1754 switch (sig) { 1758 switch (sig) {
1755 case SIGINT: 1759 case SIGINT:
1760 debug_printf_exec("%s: sig:%d default SIGINT handler\n", __func__, sig);
1756 /* Builtin was ^C'ed, make it look prettier: */ 1761 /* Builtin was ^C'ed, make it look prettier: */
1757 bb_putchar('\n'); 1762 bb_putchar('\n');
1758 G.flag_SIGINT = 1; 1763 G.flag_SIGINT = 1;
@@ -1761,6 +1766,7 @@ static int check_and_run_traps(void)
1761#if ENABLE_HUSH_JOB 1766#if ENABLE_HUSH_JOB
1762 case SIGHUP: { 1767 case SIGHUP: {
1763 struct pipe *job; 1768 struct pipe *job;
1769 debug_printf_exec("%s: sig:%d default SIGHUP handler\n", __func__, sig);
1764 /* bash is observed to signal whole process groups, 1770 /* bash is observed to signal whole process groups,
1765 * not individual processes */ 1771 * not individual processes */
1766 for (job = G.job_list; job; job = job->next) { 1772 for (job = G.job_list; job; job = job->next) {
@@ -1775,6 +1781,7 @@ static int check_and_run_traps(void)
1775#endif 1781#endif
1776#if ENABLE_HUSH_FAST 1782#if ENABLE_HUSH_FAST
1777 case SIGCHLD: 1783 case SIGCHLD:
1784 debug_printf_exec("%s: sig:%d default SIGCHLD handler\n", __func__, sig);
1778 G.count_SIGCHLD++; 1785 G.count_SIGCHLD++;
1779//bb_error_msg("[%d] check_and_run_traps: G.count_SIGCHLD:%d G.handled_SIGCHLD:%d", getpid(), G.count_SIGCHLD, G.handled_SIGCHLD); 1786//bb_error_msg("[%d] check_and_run_traps: G.count_SIGCHLD:%d G.handled_SIGCHLD:%d", getpid(), G.count_SIGCHLD, G.handled_SIGCHLD);
1780 /* Note: 1787 /* Note:
@@ -1784,6 +1791,7 @@ static int check_and_run_traps(void)
1784 break; 1791 break;
1785#endif 1792#endif
1786 default: /* ignored: */ 1793 default: /* ignored: */
1794 debug_printf_exec("%s: sig:%d default handling is to ignore\n", __func__, sig);
1787 /* SIGTERM, SIGQUIT, SIGTTIN, SIGTTOU, SIGTSTP */ 1795 /* SIGTERM, SIGQUIT, SIGTTIN, SIGTTOU, SIGTSTP */
1788 /* Note: 1796 /* Note:
1789 * We dont do 'last_sig = sig' here -> NOT returning this sig. 1797 * We dont do 'last_sig = sig' here -> NOT returning this sig.
@@ -6078,10 +6086,8 @@ static void parse_and_run_stream(struct in_str *inp, int end_trigger)
6078 debug_printf_exec("parse_and_run_stream: run_and_free_list\n"); 6086 debug_printf_exec("parse_and_run_stream: run_and_free_list\n");
6079 run_and_free_list(pipe_list); 6087 run_and_free_list(pipe_list);
6080 empty = 0; 6088 empty = 0;
6081#if ENABLE_HUSH_FUNCTIONS 6089 if (G_flag_return_in_progress == 1)
6082 if (G.flag_return_in_progress == 1)
6083 break; 6090 break;
6084#endif
6085 } 6091 }
6086} 6092}
6087 6093
@@ -6641,8 +6647,8 @@ static int run_function(const struct function *funcp, char **argv)
6641 save_and_replace_G_args(&sv, argv); 6647 save_and_replace_G_args(&sv, argv);
6642 6648
6643 /* "we are in function, ok to use return" */ 6649 /* "we are in function, ok to use return" */
6644 sv_flg = G.flag_return_in_progress; 6650 sv_flg = G_flag_return_in_progress;
6645 G.flag_return_in_progress = -1; 6651 G_flag_return_in_progress = -1;
6646# if ENABLE_HUSH_LOCAL 6652# if ENABLE_HUSH_LOCAL
6647 G.func_nest_level++; 6653 G.func_nest_level++;
6648# endif 6654# endif
@@ -6683,7 +6689,7 @@ static int run_function(const struct function *funcp, char **argv)
6683 G.func_nest_level--; 6689 G.func_nest_level--;
6684 } 6690 }
6685# endif 6691# endif
6686 G.flag_return_in_progress = sv_flg; 6692 G_flag_return_in_progress = sv_flg;
6687 6693
6688 restore_G_args(&sv, argv); 6694 restore_G_args(&sv, argv);
6689 6695
@@ -7707,6 +7713,8 @@ static int run_list(struct pipe *pi)
7707 for (; pi; pi = IF_HUSH_LOOPS(rword == RES_DONE ? loop_top : ) pi->next) { 7713 for (; pi; pi = IF_HUSH_LOOPS(rword == RES_DONE ? loop_top : ) pi->next) {
7708 if (G.flag_SIGINT) 7714 if (G.flag_SIGINT)
7709 break; 7715 break;
7716 if (G_flag_return_in_progress == 1)
7717 break;
7710 7718
7711 IF_HAS_KEYWORDS(rword = pi->res_word;) 7719 IF_HAS_KEYWORDS(rword = pi->res_word;)
7712 debug_printf_exec(": rword=%d cond_code=%d last_rword=%d\n", 7720 debug_printf_exec(": rword=%d cond_code=%d last_rword=%d\n",
@@ -7877,12 +7885,10 @@ static int run_list(struct pipe *pi)
7877 continue; 7885 continue;
7878 } 7886 }
7879#endif 7887#endif
7880#if ENABLE_HUSH_FUNCTIONS 7888 if (G_flag_return_in_progress == 1) {
7881 if (G.flag_return_in_progress == 1) {
7882 checkjobs(NULL); 7889 checkjobs(NULL);
7883 break; 7890 break;
7884 } 7891 }
7885#endif
7886 } else if (pi->followup == PIPE_BG) { 7892 } else if (pi->followup == PIPE_BG) {
7887 /* What does bash do with attempts to background builtins? */ 7893 /* What does bash do with attempts to background builtins? */
7888 /* even bash 3.2 doesn't do that well with nested bg: 7894 /* even bash 3.2 doesn't do that well with nested bg:
@@ -9271,9 +9277,9 @@ static int FAST_FUNC builtin_source(char **argv)
9271 } 9277 }
9272 9278
9273#if ENABLE_HUSH_FUNCTIONS 9279#if ENABLE_HUSH_FUNCTIONS
9274 sv_flg = G.flag_return_in_progress; 9280 sv_flg = G_flag_return_in_progress;
9275 /* "we are inside sourced file, ok to use return" */ 9281 /* "we are inside sourced file, ok to use return" */
9276 G.flag_return_in_progress = -1; 9282 G_flag_return_in_progress = -1;
9277#endif 9283#endif
9278 if (argv[1]) 9284 if (argv[1])
9279 save_and_replace_G_args(&sv, argv); 9285 save_and_replace_G_args(&sv, argv);
@@ -9286,7 +9292,7 @@ static int FAST_FUNC builtin_source(char **argv)
9286 if (argv[1]) 9292 if (argv[1])
9287 restore_G_args(&sv, argv); 9293 restore_G_args(&sv, argv);
9288#if ENABLE_HUSH_FUNCTIONS 9294#if ENABLE_HUSH_FUNCTIONS
9289 G.flag_return_in_progress = sv_flg; 9295 G_flag_return_in_progress = sv_flg;
9290#endif 9296#endif
9291 9297
9292 return G.last_exitcode; 9298 return G.last_exitcode;
@@ -9509,12 +9515,12 @@ static int FAST_FUNC builtin_return(char **argv)
9509{ 9515{
9510 int rc; 9516 int rc;
9511 9517
9512 if (G.flag_return_in_progress != -1) { 9518 if (G_flag_return_in_progress != -1) {
9513 bb_error_msg("%s: not in a function or sourced script", argv[0]); 9519 bb_error_msg("%s: not in a function or sourced script", argv[0]);
9514 return EXIT_FAILURE; /* bash compat */ 9520 return EXIT_FAILURE; /* bash compat */
9515 } 9521 }
9516 9522
9517 G.flag_return_in_progress = 1; 9523 G_flag_return_in_progress = 1;
9518 9524
9519 /* bash: 9525 /* bash:
9520 * out of range: wraps around at 256, does not error out 9526 * out of range: wraps around at 256, does not error out
diff --git a/shell/hush_test/hush-trap/return_in_trap1.right b/shell/hush_test/hush-trap/return_in_trap1.right
new file mode 100644
index 000000000..a6e637885
--- /dev/null
+++ b/shell/hush_test/hush-trap/return_in_trap1.right
@@ -0,0 +1,4 @@
1a:2
2b:0
3Trap
4d:3
diff --git a/shell/hush_test/hush-trap/return_in_trap1.tests b/shell/hush_test/hush-trap/return_in_trap1.tests
new file mode 100755
index 000000000..f2498024f
--- /dev/null
+++ b/shell/hush_test/hush-trap/return_in_trap1.tests
@@ -0,0 +1,18 @@
1a() {
2 (exit 2)
3 echo a:$?
4 (kill -s USR1 $$; echo b:$?; exit 3)
5 echo c:$? # does not execute
6 (exit 4)
7}
8
9trap "echo Trap; return" USR1
10a
11
12echo d:$?
13# It's debatable what is the correct value above.
14# Does 'return' in trap sees $? == 2 or $? == 3?
15# IOW: after (kill..), does shell first wait for its completion
16# and sets $?, then checks pending signals and runs a trap handler,
17# or does it first checks pending signals and runs handler?
18# hush does the former, and prints 3.