From 03b415d33effff1a40371d70ee799e7a08c362be Mon Sep 17 00:00:00 2001 From: Chet Ramey Date: Wed, 19 Oct 2016 15:14:38 -0400 Subject: [PATCH] commit bash-20161014 snapshot --- CWRU/CWRU.chlog | 52 +++++++++++++++++++++++++++++++++++++++++++ aclocal.m4 | 26 +++++++++------------- builtins/common.h | 1 + builtins/evalstring.c | 25 +++++++++++++++++++++ configure | 39 +++++++++++++++----------------- doc/bash.1 | 8 +++---- doc/bashref.texi | 8 +++---- execute_cmd.c | 28 +++++++++++++++++++++++ execute_cmd.h | 1 + expr.c | 20 +++++++++++++++++ jobs.c | 37 ++++++++++++++++++++++-------- lib/malloc/malloc.c | 6 ++++- parse.y | 19 +++++++++++++++- subst.c | 5 +++-- tests/RUN-ONE-TEST | 2 +- 15 files changed, 219 insertions(+), 58 deletions(-) diff --git a/CWRU/CWRU.chlog b/CWRU/CWRU.chlog index 5da68cbf..9134bbba 100644 --- a/CWRU/CWRU.chlog +++ b/CWRU/CWRU.chlog @@ -11952,3 +11952,55 @@ array.c array.c - array_remove: short-circuit if asked to remove index after max index or before first index + + 10/10 + ----- +lib/malloc/malloc.c + - internal_realloc: if we are requesting reallocation to the same size + as the block's current size, short-circuit and return `mem' right + after doing bounds check + - internal_realloc: if we are reducing the size of an allocation, and + the new size fits in the next lower bin, just keep the same block + and adjust the size, so we can avoid some copies + +parse.y + - set_line_mbstate: keep track of the allocated size of + shell_input_line_property, only request reallocation if the size + increases, but don't let it get too big + + 10/11 + ----- +jobs.c + - wait_for_background_pids: make sure we wait for pid in + last_procsub_child since it's not found in any job -- still needs + more work to wait for multiple process substitutions + +subst.c + - process_substitute: if make_child fails, make sure we call + restore_pipeline to undo the previous save_pipeline() + + 10/15 + ----- +subst.c + - process_substitute,command_substitute: leave subshell_level (reflected + as $BASH_SUBSHELL) intact for any exit trap instead of decrementing + it. Suggested by Martijn Dekker + +builtins/evalstring.c + - optimize_subshell_command: new function, framework for optimizing + out forks for command that have already forked and are executing + in a subshell. Not used yet + +expr.c + - readtok: if we have a post-increment or post-decrement, and the + previous token is not a string, check whether the previous token is + a number that results from a pre-increment or pre-decrement, and + make that an error. Report from Conrad Hoffmann + + 10/16 + ----- +aclocal.m4 + - BASH_JOB_CONTROL_MISSING: convert from AC_TRY_RUN to AC_TRY_COMPILE + with existing set of preprocessor defines, so it can work when + cross-compiling. Suggested by Felix Janda + diff --git a/aclocal.m4 b/aclocal.m4 index 007dae6c..38fe273e 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -1,4 +1,4 @@ -dnl +nl dnl Bash specific tests dnl dnl Some derived from PDKSH 5.1.3 autoconf tests @@ -1357,7 +1357,7 @@ AC_DEFUN(BASH_SYS_JOB_CONTROL_MISSING, [AC_REQUIRE([BASH_SYS_SIGNAL_VINTAGE]) AC_MSG_CHECKING(for presence of necessary job control definitions) AC_CACHE_VAL(bash_cv_job_control_missing, -[AC_TRY_RUN([ +[AC_TRY_COMPILE([ #include #ifdef HAVE_SYS_WAIT_H #include @@ -1367,42 +1367,38 @@ AC_CACHE_VAL(bash_cv_job_control_missing, #endif #include -/* Add more tests in here as appropriate. */ -main() -{ +/* add more tests in here as appropriate */ + /* signal type */ #if !defined (HAVE_POSIX_SIGNALS) && !defined (HAVE_BSD_SIGNALS) -exit(1); +#error #endif /* signals and tty control. */ #if !defined (SIGTSTP) || !defined (SIGSTOP) || !defined (SIGCONT) -exit (1); +#error #endif /* process control */ #if !defined (WNOHANG) || !defined (WUNTRACED) -exit(1); +#error #endif /* Posix systems have tcgetpgrp and waitpid. */ #if defined (_POSIX_VERSION) && !defined (HAVE_TCGETPGRP) -exit(1); +#error #endif #if defined (_POSIX_VERSION) && !defined (HAVE_WAITPID) -exit(1); +#error #endif /* Other systems have TIOCSPGRP/TIOCGPRGP and wait3. */ #if !defined (_POSIX_VERSION) && !defined (HAVE_WAIT3) -exit(1); +#error #endif -exit(0); -}], bash_cv_job_control_missing=present, bash_cv_job_control_missing=missing, - [AC_MSG_WARN(cannot check job control if cross-compiling -- defaulting to missing) - bash_cv_job_control_missing=missing] +], , bash_cv_job_control_missing=present, bash_cv_job_control_missing=missing )]) AC_MSG_RESULT($bash_cv_job_control_missing) if test $bash_cv_job_control_missing = missing; then diff --git a/builtins/common.h b/builtins/common.h index ed852305..2ac0f778 100644 --- a/builtins/common.h +++ b/builtins/common.h @@ -204,6 +204,7 @@ extern void parse_and_execute_cleanup __P((void)); extern int parse_string __P((char *, const char *, int, char **)); extern int should_suppress_fork __P((COMMAND *)); extern void optimize_fork __P((COMMAND *)); +extern void optimize_subshell_command __P((COMMAND *)); /* Functions from evalfile.c */ extern int maybe_execute_file __P((const char *, int)); diff --git a/builtins/evalstring.c b/builtins/evalstring.c index e2215914..78caaffb 100644 --- a/builtins/evalstring.c +++ b/builtins/evalstring.c @@ -127,6 +127,31 @@ optimize_fork (command) command->value.Connection->second->value.Simple->flags |= CMD_NO_FORK; } } + +void +optimize_subshell_command (command) + COMMAND *command; +{ + if (running_trap == 0 && + command->type == cm_simple && + any_signals_trapped () < 0 && + command->redirects == 0 && command->value.Simple->redirects == 0 && + ((command->flags & CMD_TIME_PIPELINE) == 0) && + ((command->flags & CMD_INVERT_RETURN) == 0)) + { +itrace("optimize_subshell_command: optimizing simple command"); + command->flags |= CMD_NO_FORK; + command->value.Simple->flags |= CMD_NO_FORK; + } + else if (command->type == cm_connection && + (command->value.Connection->connector == AND_AND || command->value.Connection->connector == OR_OR)) +{ +itrace("optimize_subshell_command: attempting to optimize connection"); + optimize_subshell_command (command->value.Connection->second); +} + else + itrace("optimize_subshell_command: command type = %d", command->type); +} /* How to force parse_and_execute () to clean up after itself. */ void diff --git a/configure b/configure index 7b377af3..9dfb06e9 100755 --- a/configure +++ b/configure @@ -15201,12 +15201,6 @@ fi $as_echo_n "checking for presence of necessary job control definitions... " >&6; } if ${bash_cv_job_control_missing+:} false; then : $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cannot check job control if cross-compiling -- defaulting to missing" >&5 -$as_echo "$as_me: WARNING: cannot check job control if cross-compiling -- defaulting to missing" >&2;} - bash_cv_job_control_missing=missing - else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -15220,51 +15214,54 @@ else #endif #include -/* Add more tests in here as appropriate. */ -main() -{ +/* add more tests in here as appropriate */ + /* signal type */ #if !defined (HAVE_POSIX_SIGNALS) && !defined (HAVE_BSD_SIGNALS) -exit(1); +#error #endif /* signals and tty control. */ #if !defined (SIGTSTP) || !defined (SIGSTOP) || !defined (SIGCONT) -exit (1); +#error #endif /* process control */ #if !defined (WNOHANG) || !defined (WUNTRACED) -exit(1); +#error #endif /* Posix systems have tcgetpgrp and waitpid. */ #if defined (_POSIX_VERSION) && !defined (HAVE_TCGETPGRP) -exit(1); +#error #endif #if defined (_POSIX_VERSION) && !defined (HAVE_WAITPID) -exit(1); +#error #endif /* Other systems have TIOCSPGRP/TIOCGPRGP and wait3. */ #if !defined (_POSIX_VERSION) && !defined (HAVE_WAIT3) -exit(1); +#error #endif -exit(0); + +int +main () +{ + + ; + return 0; } _ACEOF -if ac_fn_c_try_run "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO"; then : bash_cv_job_control_missing=present else bash_cv_job_control_missing=missing -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $bash_cv_job_control_missing" >&5 $as_echo "$bash_cv_job_control_missing" >&6; } diff --git a/doc/bash.1 b/doc/bash.1 index aacf9bcc..a1408989 100644 --- a/doc/bash.1 +++ b/doc/bash.1 @@ -2053,9 +2053,9 @@ nesting level. Function invocations that exceed this nesting level will cause the current command to abort. .TP .B GLOBIGNORE -A colon-separated list of patterns defining the set of filenames to +A colon-separated list of patterns defining the set of file names to be ignored by pathname expansion. -If a filename matched by a pathname expansion pattern also matches one +If a file name matched by a pathname expansion pattern also matches one of the patterns in .SM .BR GLOBIGNORE , @@ -3483,12 +3483,12 @@ shell options. The .SM .B GLOBIGNORE -shell variable may be used to restrict the set of filenames matching a +shell variable may be used to restrict the set of file names matching a .IR pattern . If .SM .B GLOBIGNORE -is set, each matching filename that also matches one of the patterns in +is set, each matching file name that also matches one of the patterns in .SM .B GLOBIGNORE is removed from the list of matches. diff --git a/doc/bashref.texi b/doc/bashref.texi index db57ef5b..0b443cc8 100644 --- a/doc/bashref.texi +++ b/doc/bashref.texi @@ -2421,9 +2421,9 @@ for a description of the @code{nocaseglob}, @code{nullglob}, @code{failglob}, and @code{dotglob} options. The @env{GLOBIGNORE} -shell variable may be used to restrict the set of filenames matching a +shell variable may be used to restrict the set of file names matching a pattern. If @env{GLOBIGNORE} -is set, each matching filename that also matches one of the patterns in +is set, each matching file name that also matches one of the patterns in @env{GLOBIGNORE} is removed from the list of matches. If the @code{nocaseglob} option is set, the matching against the patterns in @env{GLOBIGNORE} is performed without regard to case. @@ -5787,9 +5787,9 @@ nesting level. Function invocations that exceed this nesting level will cause the current command to abort. @item GLOBIGNORE -A colon-separated list of patterns defining the set of filenames to +A colon-separated list of patterns defining the set of file names to be ignored by filename expansion. -If a filename matched by a filename expansion pattern also matches one +If a file name matched by a filename expansion pattern also matches one of the patterns in @env{GLOBIGNORE}, it is removed from the list of matches. The pattern matching honors the setting of the @code{extglob} shell diff --git a/execute_cmd.c b/execute_cmd.c index def409f6..935ffe70 100644 --- a/execute_cmd.c +++ b/execute_cmd.c @@ -1568,6 +1568,12 @@ execute_in_subshell (command, asynchronous, pipe_in, pipe_out, fds_to_close) if (should_redir_stdin && stdin_redir == 0) async_redirect_stdin (); +#if 0 + /* bash-5.0 */ + if (user_subshell && command->type == cm_subshell) + optimize_subshell_command (command->value.Subshell->command); +#endif + /* Do redirections, then dispose of them before recursive call. */ if (command->redirects) { @@ -1876,6 +1882,17 @@ cpl_searchbyname (name) return (struct cpelement *)NULL; } +static pid_t +cpl_firstactive () +{ + struct cpelement *cpe; + + for (cpe = coproc_list.head ; cpe; cpe = cpe->next) + if ((cpe->coproc->c_flags & COPROC_DEAD) == 0) + return cpe->coproc->c_pid; + return (pid_t)NO_PID; +} + #if 0 static void cpl_prune () @@ -2147,6 +2164,15 @@ coproc_pidchk (pid, status) } } +pid_t +coproc_active () +{ +#if MULTIPLE_COPROCS + return (cpl_firstactive ()); +#else + return ((sh_coproc.c_flags & COPROC_DEAD) ? NO_PID : sh_coproc.c_pid); +#endif +} void coproc_setvars (cp) struct coproc *cp; @@ -2309,6 +2335,8 @@ execute_coproc (command, pipe_in, pipe_out, fds_to_close) cp->c_rfd = rpipe[0]; cp->c_wfd = wpipe[1]; + cp->c_flags |= COPROC_RUNNING; + SET_CLOSE_ON_EXEC (cp->c_rfd); SET_CLOSE_ON_EXEC (cp->c_wfd); diff --git a/execute_cmd.h b/execute_cmd.h index 62bec829..4f53b6f7 100644 --- a/execute_cmd.h +++ b/execute_cmd.h @@ -57,6 +57,7 @@ extern void coproc_flush __P((void)); extern void coproc_close __P((struct coproc *)); extern void coproc_closeall __P((void)); extern void coproc_reap __P((void)); +extern pid_t coproc_active __P((void)); extern void coproc_rclose __P((struct coproc *, int)); extern void coproc_wclose __P((struct coproc *, int)); diff --git a/expr.c b/expr.c index 29c4c03d..dcea480a 100644 --- a/expr.c +++ b/expr.c @@ -1368,6 +1368,14 @@ readtok () c = POWER; else if ((c == '-' || c == '+') && c1 == c && curtok == STR) c = (c == '-') ? POSTDEC : POSTINC; + else if ((c == '-' || c == '+') && c1 == c && curtok == NUM && (lasttok == PREINC || lasttok == PREDEC)) + { + /* This catches something like --FOO++ */ + if (c == '-') + evalerror ("--: assignment requires lvalue"); + else + evalerror ("++: assignment requires lvalue"); + } else if ((c == '-' || c == '+') && c1 == c) { /* Quickly scan forward to see if this is followed by optional @@ -1378,7 +1386,19 @@ readtok () if (legal_variable_starter ((unsigned char)*xp)) c = (c == '-') ? PREDEC : PREINC; else + /* Could force parsing as preinc or predec and throw an error */ +#if 0 + { + /* bash-5.0 */ + /* This catches something like --4++ */ + if (c == '-') + evalerror ("--: assignment requires lvalue"); + else + evalerror ("++: assignment requires lvalue"); + } +#else cp--; /* not preinc or predec, so unget the character */ +#endif } else if (c1 == EQ && member (c, "*/%+-&^|")) { diff --git a/jobs.c b/jobs.c index 5b8cd51e..537e992a 100644 --- a/jobs.c +++ b/jobs.c @@ -3,7 +3,7 @@ /* This file works with both POSIX and BSD systems. It implements job control. */ -/* Copyright (C) 1989-2015 Free Software Foundation, Inc. +/* Copyright (C) 1989-2016 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. @@ -2372,11 +2372,12 @@ wait_for_single_pid (pid, flags) void wait_for_background_pids () { - register int i, r, waited_for; + register int i, r; + int any_stopped, check_async; sigset_t set, oset; pid_t pid; - for (waited_for = 0;;) + for (any_stopped = 0, check_async = 1;;) { BLOCK_CHILD (set, oset); @@ -2390,6 +2391,9 @@ wait_for_background_pids () if (i > js.j_lastj && jobs[i]) itrace("wait_for_background_pids: job %d non-null after js.j_lastj (%d)", i, js.j_lastj); #endif + if (jobs[i] && STOPPED (i)) + any_stopped = 1; + if (jobs[i] && RUNNING (i) && IS_FOREGROUND (i) == 0) break; } @@ -2405,16 +2409,31 @@ wait_for_background_pids () QUIT; errno = 0; /* XXX */ r = wait_for_single_pid (pid, 1); - if (r == -1) + if (r == -1 && errno == ECHILD) { /* If we're mistaken about job state, compensate. */ - if (errno == ECHILD) - mark_all_jobs_as_dead (); + check_async = 0; + mark_all_jobs_as_dead (); } - else - waited_for++; } +#if defined (PROCESS_SUBSTITUTION) + if (last_procsub_child && last_procsub_child->pid != NO_PID) + r = wait_for (last_procsub_child->pid); +#if 1 + /* We don't want to wait indefinitely if we have stopped children. */ + if (any_stopped == 0) + { + /* Check whether or not we have any unreaped children. */ + while ((r = wait_for (ANY_PID)) >= 0) + { + QUIT; + CHECK_WAIT_INTR; + } + } +#endif +#endif + /* POSIX.2 says the shell can discard the statuses of all completed jobs if `wait' is called with no arguments. */ mark_dead_jobs_as_notified (1); @@ -2667,7 +2686,7 @@ wait_for (pid) job to finish. Otherwise, we are waiting for the child to finish. We check for JDEAD in case the job state has been set by waitchld after receipt of a SIGCHLD. */ - if (job == NO_JOB) /* XXX -- && pid != ANY_PID ? */ + if (job == NO_JOB && pid != ANY_PID) /* XXX -- && pid != ANY_PID ? */ job = find_job (pid, 0, NULL); /* waitchld() takes care of setting the state of the job. If the job diff --git a/lib/malloc/malloc.c b/lib/malloc/malloc.c index 053305fc..68fb5e79 100644 --- a/lib/malloc/malloc.c +++ b/lib/malloc/malloc.c @@ -1033,11 +1033,15 @@ internal_realloc (mem, n, file, line, flags) _mstats.bytesreq += (n < tocopy) ? 0 : n - tocopy; #endif + /* If we're reallocating to the same size as previously, return now */ + if (n == p->mh_nbytes) + return mem; + /* See if desired size rounds to same power of 2 as actual size. */ nbytes = ALLOCATED_BYTES(n); /* If ok, use the same block, just marking its size as changed. */ - if (RIGHT_BUCKET(nbytes, nunits)) + if (RIGHT_BUCKET(nbytes, nunits) || RIGHT_BUCKET(nbytes, nunits-1)) { #if 0 m = (char *)mem + p->mh_nbytes; diff --git a/parse.y b/parse.y index 6076a1a6..7c81f3c1 100644 --- a/parse.y +++ b/parse.y @@ -218,6 +218,7 @@ static void print_prompt __P((void)); #if defined (HANDLE_MULTIBYTE) static void set_line_mbstate __P((void)); static char *shell_input_line_property = NULL; +static size_t shell_input_line_propsize = 0; #else # define set_line_mbstate() #endif @@ -6481,6 +6482,10 @@ restore_input_line_state (ls) ************************************************/ #if defined (HANDLE_MULTIBYTE) + +/* We don't let the property buffer get larger than this unless the line is */ +#define MAX_PROPSIZE 32768 + static void set_line_mbstate () { @@ -6492,7 +6497,19 @@ set_line_mbstate () if (shell_input_line == NULL) return; len = strlen (shell_input_line); /* XXX - shell_input_line_len ? */ - shell_input_line_property = (char *)xrealloc (shell_input_line_property, len + 1); + if (len == 0) + return; + if (shell_input_line_propsize >= MAX_PROPSIZE && len < MAX_PROPSIZE>>1) + { + free (shell_input_line_property); + shell_input_line_property = 0; + shell_input_line_propsize = 0; + } + if (len+1 > shell_input_line_propsize) + { + shell_input_line_propsize = len + 1; + shell_input_line_property = (char *)xrealloc (shell_input_line_property, shell_input_line_propsize); + } memset (&prevs, '\0', sizeof (mbstate_t)); for (i = previ = 0; i < len; i++) diff --git a/subst.c b/subst.c index 2c874f99..be767f2f 100644 --- a/subst.c +++ b/subst.c @@ -5802,6 +5802,7 @@ process_substitute (string, open_for_read_in_child) close (parent_pipe_fd); close (child_pipe_fd); #endif /* HAVE_DEV_FD */ + restore_pipeline (1); return ((char *)NULL); } @@ -5904,7 +5905,7 @@ process_substitute (string, open_for_read_in_child) subshell_level++; result = parse_and_execute (string, "process substitution", (SEVAL_NONINT|SEVAL_NOHIST)); - subshell_level--; + /* 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. */ @@ -6241,7 +6242,7 @@ command_substitute (string, quoted) { subshell_level++; rc = parse_and_execute (string, "command substitution", pflags|SEVAL_NOHIST); - subshell_level--; + /* leave subshell level intact for any exit trap */ } last_command_exit_value = rc; diff --git a/tests/RUN-ONE-TEST b/tests/RUN-ONE-TEST index d29259a9..a5ab273d 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