diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2016-10-01 22:28:03 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2016-10-01 22:28:03 +0200 |
commit | 04b46bced991f802a17c0fc43c8f8448e4eb2c8f (patch) | |
tree | fa9f4f151950d21aca3bbf9a3c4bfa01853976cc | |
parent | 0dd8e45d42a420a570e7cada80a5fb1ef2052054 (diff) | |
download | busybox-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.c | 34 | ||||
-rw-r--r-- | shell/hush_test/hush-trap/return_in_trap1.right | 4 | ||||
-rwxr-xr-x | shell/hush_test/hush-trap/return_in_trap1.tests | 18 |
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 @@ | |||
1 | a:2 | ||
2 | b:0 | ||
3 | Trap | ||
4 | d: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 @@ | |||
1 | a() { | ||
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 | |||
9 | trap "echo Trap; return" USR1 | ||
10 | a | ||
11 | |||
12 | echo 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. | ||