From d155fbc5fd8244659631c4d7eedb7228b5f3c3f8 Mon Sep 17 00:00:00 2001 From: Chet Ramey Date: Thu, 12 Apr 2018 15:09:21 -0400 Subject: [PATCH] commit bash-20180406 snapshot --- CWRU/CWRU.chlog | 60 +++++++++++++++++++++++++++++++++++++ MANIFEST | 2 ++ execute_cmd.c | 27 ++++++++++++----- execute_cmd.h | 9 ++++++ jobs.c | 12 +++++++- lib/glob/smatch.c | 46 +++++++++++++++++++++++++++- lib/readline/doc/readline.3 | 1 + parse.y | 3 +- pathexp.h | 1 + subst.c | 37 ++++++++++++++++++----- tests/RUN-ONE-TEST | 2 +- tests/case.right | 16 ++++++++++ tests/case.tests | 1 + tests/case3.sub | 37 +++++++++++++++++++++++ tests/heredoc.right | 8 +++++ tests/heredoc.tests | 2 +- tests/heredoc4.sub | 12 ++++++++ tests/jobs.right | 10 +++---- tests/trap.right | 8 +++++ tests/trap2.sub | 24 +++++++++++++++ 20 files changed, 294 insertions(+), 24 deletions(-) create mode 100644 tests/case3.sub create mode 100644 tests/heredoc4.sub diff --git a/CWRU/CWRU.chlog b/CWRU/CWRU.chlog index fbc27678a..dfe2bd8ca 100644 --- a/CWRU/CWRU.chlog +++ b/CWRU/CWRU.chlog @@ -15137,3 +15137,63 @@ lib/readline/bind.c to accommodate symbolic key sequences; should be a no-op for `raw' key sequences such as the arrow key seqeunces from terminfo. Change from Koichi Murase + + 4/2 + --- +jobs.c + - wait_for: when setting the SIGINT signal handler to wait_sigint_handler + make sure we're not setting old_sigint_handler recursively, as we + can when running an external command in a trap we took after a + command exited due to SIGINT. We don't want to overwrite + old_sigint_handler here. Fixes bug reported by Dr. Werner Fink + + +execute_cmd.c + - execute_disk_command: when there is a command_not_found_hook, make + sure the subshell turns off job control before running it, in case + it runs processes. We don't want it to manipulate process groups. + Fixes bug reported by ÐиÑиллов Ðима + - execute_command_internal: make sure the command run by the `command' + builtin doesn't cause the ERR trap to be executed; wait for the + status to be returned by the command builtin. Fixes bug reported by + Martijn Dekker + + 4/4 + --- +subst.c + - process_substitute: handle longjmp back to top_level and function + returns (return_catch) in the child process, like command + substitution, so we don't longjmp back to some arbitrary spot from + the `exit' or `return' builtins, or on an expansion error, like + the command timing code. Fixes bug reported by Basin Ilya + + + 4/6 + --- +parse.y + - read_token_word: when reading a matched pair of backquotes as part + of a word, treat it as quoted so the characters are read as a single + word, but do not let the presence of the backquote mark the word as + quoted. Fixes here-document delimiter bug reported by Denys Vlasenko + + + 4/7 + --- +execute_cmd.c + - execute_case_command: call quote_string_for_globbing with the + QGLOB_CTLESC flag for both quoted and unquoted words, so it will + remove CTLESC/CTLESC in all cases while converting other quoted + characters to use a preceding backslash. Bug reported by + Martijn Dekker + + 4/9 + --- +smatch.c + - posix_cclass_only: helper function that checks whether a pattern has + only posix single-byte character classes ([:alpha:], etc.) or has + none at all + - xstrmatch: if running in a multibyte locale, make sure to short- + circuit to the single-byte matching code only if there are no + unrecognized character class names, since the wide character ctype + functions allow locales to define their own character class names + (e.g., "hyphen"). Fixes issue reported by yangyajing diff --git a/MANIFEST b/MANIFEST index 235bd9e41..00a577938 100644 --- a/MANIFEST +++ b/MANIFEST @@ -903,6 +903,7 @@ tests/case.tests f tests/case.right f tests/case1.sub f tests/case2.sub f +tests/case3.sub f tests/casemod.tests f tests/casemod.right f tests/comsub.tests f @@ -1058,6 +1059,7 @@ tests/heredoc.right f tests/heredoc1.sub f tests/heredoc2.sub f tests/heredoc3.sub f +tests/heredoc4.sub f tests/herestr.tests f tests/herestr.right f tests/herestr1.sub f diff --git a/execute_cmd.c b/execute_cmd.c index 66d235408..0ac260306 100644 --- a/execute_cmd.c +++ b/execute_cmd.c @@ -873,8 +873,13 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out, } /* 2009/02/13 -- pipeline failure is processed elsewhere. This handles - only the failure of a simple command. */ - if (was_error_trap && ignore_return == 0 && invert == 0 && pipe_in == NO_PIPE && pipe_out == NO_PIPE && exec_result != EXECUTION_SUCCESS) + only the failure of a simple command. We don't want to run the error + trap if the command run by the `command' builtin fails; we want to + defer that until the command builtin itself returns failure. */ + if (was_error_trap && ignore_return == 0 && invert == 0 && + pipe_in == NO_PIPE && pipe_out == NO_PIPE && + (command->value.Simple->flags & CMD_COMMAND_BUILTIN) == 0 && + exec_result != EXECUTION_SUCCESS) { last_command_exit_value = exec_result; line_number = line_number_for_err_trap; @@ -1421,6 +1426,7 @@ time_command (command, asynchronous, pipe_in, pipe_out, fds_to_close) else time_format = BASH_TIMEFORMAT; } + if (time_format && *time_format) print_formatted_time (stderr, time_format, rs, rsf, us, usf, ss, ssf, cpu); @@ -3464,12 +3470,15 @@ execute_case_command (case_command) if (es && es->word && es->word->word && *(es->word->word)) { + /* Convert quoted null strings into empty strings. */ qflags = QGLOB_CVTNULL; + /* We left CTLESC in place quoting CTLESC after the call to expand_word_leave_quoted; tell quote_string_for_globbing to - remove those here */ - if ((list->word->flags & W_QUOTED) == 0) - qflags |= QGLOB_CTLESC; + remove those here. This works for both unquoted portions of + the word (which call quote_escapes) and quoted portions + (which call quote_string). */ + qflags |= QGLOB_CTLESC; pattern = quote_string_for_globbing (es->word->word, qflags); } else @@ -5375,9 +5384,13 @@ execute_disk_command (words, redirects, command_line, pipe_in, pipe_out, exit (EX_NOTFOUND); /* Posix.2 says the exit status is 127 */ } + /* We don't want to manage process groups for processes we start + from here, so we turn off job control and don't attempt to + manipulate the terminal's process group. */ + without_job_control (); + #if defined (JOB_CONTROL) - /* May need to reinitialize more of the job control state here. */ - kill_current_pipeline (); + set_sigchld_handler (); #endif wl = make_word_list (make_word (NOTFOUND_HOOK), words); diff --git a/execute_cmd.h b/execute_cmd.h index 4025de843..dc2f15ec6 100644 --- a/execute_cmd.h +++ b/execute_cmd.h @@ -35,6 +35,15 @@ struct func_array_state }; #endif +/* Placeholder for later expansion to include more execution state */ +/* XXX - watch out for pid_t */ +struct execstate + { + pid_t pid; + int subshell_env; + }; + + /* Variables delared in execute_cmd.c, used by many other files */ extern int return_catch_flag; extern int return_catch_value; diff --git a/jobs.c b/jobs.c index 8e51fa9b3..45ee572d9 100644 --- a/jobs.c +++ b/jobs.c @@ -2723,7 +2723,17 @@ wait_for (pid) wait_sigint_received = child_caught_sigint = 0; if (job_control == 0 || (subshell_environment&SUBSHELL_COMSUB)) { - old_sigint_handler = set_signal_handler (SIGINT, wait_sigint_handler); + SigHandler *temp_sigint_handler; + + temp_sigint_handler = set_signal_handler (SIGINT, wait_sigint_handler); + if (temp_sigint_handler == wait_sigint_handler) + { +#if defined (DEBUG) + internal_warning ("wait_for: recursively setting old_sigint_handler to wait_sigint_handler: running_trap = %d", running_trap); +#endif + } + else + old_sigint_handler = temp_sigint_handler; waiting_for_child = 0; if (old_sigint_handler == SIG_IGN) set_signal_handler (SIGINT, old_sigint_handler); diff --git a/lib/glob/smatch.c b/lib/glob/smatch.c index 9032c41a6..025fe4fca 100644 --- a/lib/glob/smatch.c +++ b/lib/glob/smatch.c @@ -380,6 +380,50 @@ is_wcclass (wc, name) return (iswctype (wc, desc)); } +/* Return 1 if there are no char class [:class:] expressions (degenerate case) + or only posix-specified (C locale supported) char class expressions in + PATTERN. These are the ones where it's safe to punt to the single-byte + code, since wide character support allows locale-defined char classes. + This only uses single-byte code, but is only needed to support multibyte + locales. */ +static int +posix_cclass_only (pattern) + char *pattern; +{ + char *p, *p1; + char cc[16]; /* sufficient for all valid posix char class names */ + enum char_class valid; + + p = pattern; + while (p = strchr (p, '[')) + { + if (p[1] != ':') + { + p++; + continue; + } + p += 2; /* skip past "[:" */ + /* Find end of char class expression */ + for (p1 = p; *p1; p1++) + if (*p1 == ':' && p1[1] == ']') + break; + if (*p1 == 0) /* no char class expression found */ + break; + /* Find char class name and validate it against posix char classes */ + if ((p1 - p) >= sizeof (cc)) + return 0; + bcopy (p, cc, p1 - p); + cc[p1 - p] = '\0'; + valid = is_valid_cclass (cc); + if (valid == CC_NO_CLASS) + return 0; /* found unrecognized char class name */ + + p = p1 + 2; /* found posix char class name */ + } + + return 1; /* no char class names or only posix */ +} + /* Now include `sm_loop.c' for multibyte characters. */ #define FOLD(c) ((flags & FNM_CASEFOLD) && iswupper (c) ? towlower (c) : (c)) #define FCT internal_wstrmatch @@ -419,7 +463,7 @@ xstrmatch (pattern, string, flags) if (MB_CUR_MAX == 1) return (internal_strmatch ((unsigned char *)pattern, (unsigned char *)string, flags)); - if (mbsmbchar (string) == 0 && mbsmbchar (pattern) == 0) + if (mbsmbchar (string) == 0 && mbsmbchar (pattern) == 0 && posix_cclass_only (pattern) ) return (internal_strmatch ((unsigned char *)pattern, (unsigned char *)string, flags)); n = xdupmbstowcs (&wpattern, NULL, pattern); diff --git a/lib/readline/doc/readline.3 b/lib/readline/doc/readline.3 index c084c6586..be89c2dff 100644 --- a/lib/readline/doc/readline.3 +++ b/lib/readline/doc/readline.3 @@ -1149,6 +1149,7 @@ and store the definition. .B call\-last\-kbd\-macro (C\-x e) Re-execute the last keyboard macro defined, by making the characters in the macro appear as if typed at the keyboard. +.TP .B print\-last\-kbd\-macro () Print the last keyboard macro defined in a format suitable for the \fIinputrc\fP file. diff --git a/parse.y b/parse.y index 274bb0e13..b88962efd 100644 --- a/parse.y +++ b/parse.y @@ -4946,7 +4946,8 @@ read_token_word (character) strcpy (token + token_index, ttok); token_index += ttoklen; all_digit_token = 0; - quoted = 1; + if (character != '`') + quoted = 1; dollar_present |= (character == '"' && strchr (ttok, '$') != 0); FREE (ttok); goto next_character; diff --git a/pathexp.h b/pathexp.h index 5a69f2f68..adef8b2a1 100644 --- a/pathexp.h +++ b/pathexp.h @@ -34,6 +34,7 @@ extern char *glob_error_return; #define QGLOB_FILENAME 0x02 /* do correct quoting for matching filenames */ #define QGLOB_REGEXP 0x04 /* quote an ERE for regcomp/regexec */ #define QGLOB_CTLESC 0x08 /* turn CTLESC CTLESC into CTLESC for BREs */ +#define QGLOB_DEQUOTE 0x10 /* like dequote_string but quote glob chars */ #if defined (EXTENDED_GLOB) /* Flags to OR with other flag args to strmatch() to enabled the extended diff --git a/subst.c b/subst.c index 488becdfd..1f364cf62 100644 --- a/subst.c +++ b/subst.c @@ -5713,7 +5713,7 @@ process_substitute (string, open_for_read_in_child) int open_for_read_in_child; { char *pathname; - int fd, result; + int fd, result, rc, function_value; pid_t old_pid, pid; #if defined (HAVE_DEV_FD) int parent_pipe_fd, child_pipe_fd; @@ -5903,18 +5903,41 @@ process_substitute (string, open_for_read_in_child) remove_quoted_escapes (string); - subshell_level++; - result = parse_and_execute (string, "process substitution", (SEVAL_NONINT|SEVAL_NOHIST)); - /* leave subshell level intact for any exit trap */ + /* Give process substitution a place to jump back to on failure, + so we don't go back up to main (). */ + result = setjmp_nosigs (top_level); + + /* If we're running a process substitution inside a shell function, + trap `return' so we don't return from the function in the subshell + and go off to never-never land. */ + if (result == 0 && return_catch_flag) + function_value = setjmp_nosigs (return_catch); + else + function_value = 0; + + if (result == ERREXIT) + rc = last_command_exit_value; + else if (result == EXITPROG) + rc = last_command_exit_value; + else if (result) + rc = EXECUTION_FAILURE; + else if (function_value) + rc = return_catch_value; + else + { + subshell_level++; + rc = parse_and_execute (string, "process substitution", (SEVAL_NONINT|SEVAL_NOHIST)); + /* leave subshell level intact for any exit trap */ + } #if !defined (HAVE_DEV_FD) /* Make sure we close the named pipe in the child before we exit. */ close (open_for_read_in_child ? 0 : 1); #endif /* !HAVE_DEV_FD */ - last_command_exit_value = result; - result = run_exit_trap (); - exit (result); + last_command_exit_value = rc; + rc = run_exit_trap (); + exit (rc); /*NOTREACHED*/ } #endif /* PROCESS_SUBSTITUTION */ diff --git a/tests/RUN-ONE-TEST b/tests/RUN-ONE-TEST index 58c375b70..554f3d6ec 100755 --- a/tests/RUN-ONE-TEST +++ b/tests/RUN-ONE-TEST @@ -1,4 +1,4 @@ -BUILD_DIR=/usr/local/build/chet/bash/bash-current +BUILD_DIR=/usr/local/build/bash/bash-current THIS_SH=$BUILD_DIR/bash PATH=$PATH:$BUILD_DIR diff --git a/tests/case.right b/tests/case.right index 91cbea2ea..fc3a1285e 100644 --- a/tests/case.right +++ b/tests/case.right @@ -36,3 +36,19 @@ ok 5 ok 6 ok 7 ok 8 +--- testing: soh +ok1ok2ok3ok4ok5 +ok1ok2ok3ok4ok5 +ok1ok2ok3ok4ok5 +ok1ok2ok3ok4ok5 +ok1ok2ok3ok4ok5 +ok1ok2ok3ok4ok5 +ok1ok2ok3ok4ok5 +--- testing: stx +ok1ok2ok3ok4ok5 +ok1ok2ok3ok4ok5 +ok1ok2ok3ok4ok5 +ok1ok2ok3ok4ok5 +ok1ok2ok3ok4ok5 +ok1ok2ok3ok4ok5 +ok1ok2ok3ok4ok5 diff --git a/tests/case.tests b/tests/case.tests index ef25054f7..cc73d8e18 100644 --- a/tests/case.tests +++ b/tests/case.tests @@ -52,3 +52,4 @@ case " " in ( [" "] ) echo ok;; ( * ) echo no;; esac # tests of quote removal and pattern matching ${THIS_SH} ./case1.sub ${THIS_SH} ./case2.sub +${THIS_SH} ./case3.sub diff --git a/tests/case3.sub b/tests/case3.sub new file mode 100644 index 000000000..6b9871535 --- /dev/null +++ b/tests/case3.sub @@ -0,0 +1,37 @@ +#!/bin/sh + +testmatch() { + case $1 in + ( $2 ) printf ok1 ;; + ( * ) printf fail1 ;; + esac + case $1,$2 in + ( $2,"$2" ) printf ok2 ;; + ( * ) printf fail2 ;; + esac + case $1, in + ( $2, ) printf ok3 ;; + ( * ) printf fail3 ;; + esac + case ,$2 in + ( ,"$2" ) printf ok4 ;; + ( * ) printf fail4 ;; + esac + case "$1,$2" in + ( $2,"$2" ) printf ok5 ;; + ( * ) printf fail5 ;; + esac + echo +} + +for c in $'\1' $'\2'; do + echo -n "--- testing: " + echo "$c" | od -t a | awk 'NR==1 { print $2 } ' + testmatch "${c}" "\\${c}" + testmatch "${c}x" "\\${c}\\x" # bash-git fails case 2 and 5 for $'\1' + testmatch "${c}x" "${c}\\x" + testmatch "${c}x" "${c}x" + testmatch "${c}x" "\\${c}x" + testmatch "x${c}" "\\x\\${c}" + testmatch "x${c}" "x\\${c}" +done diff --git a/tests/heredoc.right b/tests/heredoc.right index 5e596a605..f6541dcaf 100644 --- a/tests/heredoc.right +++ b/tests/heredoc.right @@ -84,6 +84,14 @@ hello end hello\END ./heredoc3.sub: line 85: warning: here-document at line 83 delimited by end-of-file (wanted `EOF') ./heredoc3.sub: line 86: syntax error: unexpected end of file +heredoc1 +EOF +Ok:0 +argv[1] = +argv[2] = +argv[1] = +argv[2] = +argv[3] = comsub here-string ./heredoc.tests: line 105: warning: here-document at line 103 delimited by end-of-file (wanted `EOF') hi diff --git a/tests/heredoc.tests b/tests/heredoc.tests index ba74e3b6a..303949f48 100644 --- a/tests/heredoc.tests +++ b/tests/heredoc.tests @@ -90,8 +90,8 @@ ${THIS_SH} ./heredoc1.sub # test heredocs in command substitutions ${THIS_SH} ./heredoc2.sub - ${THIS_SH} ./heredoc3.sub +${THIS_SH} ./heredoc4.sub echo $( cat <<< "comsub here-string" diff --git a/tests/heredoc4.sub b/tests/heredoc4.sub new file mode 100644 index 000000000..381b64a97 --- /dev/null +++ b/tests/heredoc4.sub @@ -0,0 +1,12 @@ +cat <