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 /shell | |
| 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>
Diffstat (limited to 'shell')
| -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. | ||
