diff --git a/CWRU/CWRU.chlog b/CWRU/CWRU.chlog index 249d8425..1cacea20 100644 --- a/CWRU/CWRU.chlog +++ b/CWRU/CWRU.chlog @@ -15318,3 +15318,43 @@ subst.c to the flags passed to quote_string_for_globbing. Same issue as the one with `case' fixed on 4/7, report from Martijn Dekker + + 4/30 + ---- +redir.c + - do_redirection_internal: r_close_this: if the file descriptor is + already closed before the shell is asked to close it, make sure to + add an undo list redirect to make sure it stays closed. Report from + Martijn Dekker + + 5/2 + --- +variables.c + - push_posix_temp_var: new function, takes the SHELL_VAR * passed as + an argument and uses the name and value to create a global variable + - merge_temporary_env: if posixly_correct is set, call + push_posix_temp_var to create global variables, otherwise call + push_temp_var to preserve the old behavior. Right now, it's only + called when in posix mode, but that might change. This undoes the + change from 4/27 when in posix mode + + 5/3 + --- +sig.c + - struct that holds the terminating signal information has a new + field: whether that signal is expected to cause a core dump + - termsig_handler: if the call to kill(2) doesn't kill the process, + we have a problem. If our pid is not 1, we just exit with status + 128+sig (fake the sig exit status). If the pid is 1, we assume + we're in a Linux pid namespace and aren't allowed to send a signal + to ourselves. If we need to generate a core dump, we try to get + the kernel to SIGSEGV us by dereferencing location 0. If not, we + just exit with 128+sig. From a report and patch from Andrei Vagin + + + 5/4 + --- +bashline.c + - bash_execute_unix_command: make sure that parse_and_execute is called + with newly-allocated memory to avoid prematurely freeing the + command. Report and fix from Koichi Murase diff --git a/bashline.c b/bashline.c index 91d44465..ae8fe1cc 100644 --- a/bashline.c +++ b/bashline.c @@ -4147,7 +4147,7 @@ bash_execute_unix_command (count, key) array_needs_making = 1; save_parser_state (&ps); - r = parse_and_execute (cmd, "bash_execute_unix_command", SEVAL_NOHIST|SEVAL_NOFREE); + r = parse_and_execute (savestring (cmd), "bash_execute_unix_command", SEVAL_NOHIST|SEVAL_NOFREE); restore_parser_state (&ps); v = find_variable ("READLINE_LINE"); diff --git a/builtins/builtin.def b/builtins/builtin.def index b09246c4..74060ee0 100644 --- a/builtins/builtin.def +++ b/builtins/builtin.def @@ -31,7 +31,7 @@ as a shell function, but need to execute the builtin within the function. Exit Status: Returns the exit status of SHELL-BUILTIN, or false if SHELL-BUILTIN is -not a shell builtin.. +not a shell builtin. $END #include diff --git a/doc/bashref.texi b/doc/bashref.texi index 04da396d..f9f42536 100644 --- a/doc/bashref.texi +++ b/doc/bashref.texi @@ -6065,7 +6065,7 @@ as the sole input. If set, the value denotes the number of consecutive @code{EOF} characters that can be read as the first character on an input line before the shell will exit. If the variable exists but does not -have a numeric value (or has no value) then the default is 10. +have a numeric value, or has no value, then the default is 10. If the variable does not exist, then @code{EOF} signifies the end of input to the shell. This is only in effect for interactive shells. diff --git a/redir.c b/redir.c index ebb2c635..f5276dc6 100644 --- a/redir.c +++ b/redir.c @@ -1142,9 +1142,12 @@ do_redirection_internal (redirect, flags) r = 0; /* XXX - only if REDIR_VARASSIGN not set? */ - if ((flags & RX_UNDOABLE) && (fcntl (redirector, F_GETFD, 0) != -1)) + if (flags & RX_UNDOABLE) { - r = add_undo_redirect (redirector, ri, -1); + if (fcntl (redirector, F_GETFD, 0) != -1) + r = add_undo_redirect (redirector, ri, -1); + else + r = add_undo_close_redirect (redirector); REDIRECTION_ERROR (r, errno, redirector); } diff --git a/sig.c b/sig.c index ac2ff1f3..6934f4f9 100644 --- a/sig.c +++ b/sig.c @@ -1,6 +1,6 @@ /* sig.c - interface for shell signal handlers and signal initialization. */ -/* Copyright (C) 1994-2015 Free Software Foundation, Inc. +/* Copyright (C) 1994-2018 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. @@ -113,6 +113,7 @@ struct termsig { int signum; SigHandler *orig_handler; int orig_flags; + int core_dump; }; #define NULL_HANDLER (SigHandler *)SIG_DFL @@ -130,15 +131,15 @@ static struct termsig terminating_signals[] = { #endif #ifdef SIGILL -{ SIGILL, NULL_HANDLER, 0 }, +{ SIGILL, NULL_HANDLER, 0, 1}, #endif #ifdef SIGTRAP -{ SIGTRAP, NULL_HANDLER, 0 }, +{ SIGTRAP, NULL_HANDLER, 0, 1 }, #endif #ifdef SIGIOT -{ SIGIOT, NULL_HANDLER, 0 }, +{ SIGIOT, NULL_HANDLER, 0, 1 }, #endif #ifdef SIGDANGER @@ -150,19 +151,19 @@ static struct termsig terminating_signals[] = { #endif #ifdef SIGFPE -{ SIGFPE, NULL_HANDLER, 0 }, +{ SIGFPE, NULL_HANDLER, 0, 1 }, #endif #ifdef SIGBUS -{ SIGBUS, NULL_HANDLER, 0 }, +{ SIGBUS, NULL_HANDLER, 0, 1 }, #endif #ifdef SIGSEGV -{ SIGSEGV, NULL_HANDLER, 0 }, +{ SIGSEGV, NULL_HANDLER, 0, 1 }, #endif #ifdef SIGSYS -{ SIGSYS, NULL_HANDLER, 0 }, +{ SIGSYS, NULL_HANDLER, 0, 1 }, #endif #ifdef SIGPIPE @@ -177,12 +178,14 @@ static struct termsig terminating_signals[] = { { SIGTERM, NULL_HANDLER, 0 }, #endif +/* These don't generate core dumps on anything but Linux, but we're doing + this just for Linux anyway. */ #ifdef SIGXCPU -{ SIGXCPU, NULL_HANDLER, 0 }, +{ SIGXCPU, NULL_HANDLER, 0, 1 }, #endif #ifdef SIGXFSZ -{ SIGXFSZ, NULL_HANDLER, 0 }, +{ SIGXFSZ, NULL_HANDLER, 0, 1 }, #endif #ifdef SIGVTALRM @@ -213,6 +216,7 @@ static struct termsig terminating_signals[] = { #define XSIG(x) (terminating_signals[x].signum) #define XHANDLER(x) (terminating_signals[x].orig_handler) #define XSAFLAGS(x) (terminating_signals[x].orig_flags) +#define XCOREDUMP(x) (terminating_signals[x].core_dump) static int termsigs_initialized = 0; @@ -360,7 +364,6 @@ reset_terminating_signals () termsigs_initialized = 0; } -#undef XSIG #undef XHANDLER /* Run some of the cleanups that should be performed when we run @@ -542,6 +545,8 @@ termsig_handler (sig) int sig; { static int handling_termsig = 0; + int i, core; + sigset_t mask; /* Simple semaphore to keep this function from being executed multiple times. Since we no longer are running as a signal handler, we don't @@ -583,11 +588,39 @@ termsig_handler (sig) executing_list = comsub_ignore_return = return_catch_flag = wait_intr_flag = 0; run_exit_trap (); /* XXX - run exit trap possibly in signal context? */ + + /* We don't change the set of blocked signals. If a user starts the shell + with a terminating signal blocked, we won't get here (and if by some + magic chance we do, we'll exit below). */ set_signal_handler (sig, SIG_DFL); + kill (getpid (), sig); - exit (1); /* just in case the kill fails? */ + if (dollar_dollar_pid != 1) + exit (128+sig); /* just in case the kill fails? */ + + /* We are PID 1, and the kill above failed to kill the process. We assume + this means that we are running as an init process in a pid namespace + on Linux. In this case, we can't send ourselves a fatal signal, so we + determine whether or not we should have generated a core dump with the + kill call and attempt to trick the kernel into generating one if + necessary. */ + sigprocmask (SIG_SETMASK, (sigset_t *)NULL, &mask); + for (i = core = 0; i < TERMSIGS_LENGTH; i++) + { + set_signal_handler (XSIG (i), SIG_DFL); + sigdelset (&mask, XSIG (i)); + if (sig == XSIG (i)) + core = XCOREDUMP (i); + } + sigprocmask (SIG_SETMASK, &mask, (sigset_t *)NULL); + + if (core) + *((volatile unsigned long *) NULL) = 0xdead0000 + sig; /* SIGSEGV */ + + exit (128+sig); } +#undef XSIG /* What we really do when SIGINT occurs. */ sighandler diff --git a/tests/RUN-ONE-TEST b/tests/RUN-ONE-TEST index 554f3d6e..58c375b7 100755 --- a/tests/RUN-ONE-TEST +++ b/tests/RUN-ONE-TEST @@ -1,4 +1,4 @@ -BUILD_DIR=/usr/local/build/bash/bash-current +BUILD_DIR=/usr/local/build/chet/bash/bash-current THIS_SH=$BUILD_DIR/bash PATH=$PATH:$BUILD_DIR diff --git a/tests/procsub.right b/tests/procsub.right index 0d10aba4..cf1dbb10 100644 --- a/tests/procsub.right +++ b/tests/procsub.right @@ -3,7 +3,7 @@ foo test2 test3 test4 - 8 +8 test5 test6 test7 @@ -15,15 +15,15 @@ bye l8r :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: intern - 1 - 0 - 0 - 0 - 0 +1 +0 +0 +0 +0 extern - 1 - 0 - 0 - 0 - 0 +1 +0 +0 +0 +0 123 diff --git a/tests/procsub.tests b/tests/procsub.tests index cbd74b00..4678ac69 100644 --- a/tests/procsub.tests +++ b/tests/procsub.tests @@ -1,4 +1,5 @@ # process substitution constructs that have caused problems in the past +. ./test-glue-functions eval cat <(echo test1) eval "echo foo;cat" <(echo test2) @@ -13,7 +14,7 @@ unset f FN=$TMPDIR/bashtest-procsub-$$ cat >"$FN" </dev/null; ls -l "$1" >/dev/null; }; moo >(true) -moo() { ls -al "$1" >/dev/null; (true); ls -al "$1" >/dev/null; }; moo >(true) - -unset -f moo +# set up conditions for test +ulimit -n 256 bug() { @@ -76,7 +75,7 @@ count_lines() } echo intern -count_lines <(date) +count_lines <(date) | _cut_leading_spaces unset -f count_lines echo extern @@ -89,7 +88,12 @@ true | wc -l < \$1 wc -l < \$1 EOF -${THIS_SH} -c "source $FN <(date)" +${THIS_SH} -c "source $FN <(date)" | _cut_leading_spaces rm -f $FN +moo() { ls -l "$1" >/dev/null; ls -l "$1" >/dev/null; }; moo >(true) +moo() { ls -al "$1" >/dev/null; (true); ls -al "$1" >/dev/null; }; moo >(true) + +unset -f moo + ${THIS_SH} ./procsub1.sub diff --git a/tests/test-glue-functions b/tests/test-glue-functions index 2b2f61d0..b958ab71 100644 --- a/tests/test-glue-functions +++ b/tests/test-glue-functions @@ -6,4 +6,8 @@ _intl_normalize_spaces() sed -e 's/[[:space:]]\{1,\}/ /g' -e 's/[[:space:]]*$//' } - +# avoid whitespace differences in wc implementations +_cut_leading_spaces() +{ + sed -e 's/^[[:space:]]*//g' +} diff --git a/tests/varenv.right b/tests/varenv.right index c1eac7fb..01301719 100644 --- a/tests/varenv.right +++ b/tests/varenv.right @@ -135,6 +135,7 @@ declare -a bar=([0]="zero" [1]="one") declare -A foo=([one]="one" [zero]="zero" ) declare -a bar=([0]="zero" [1]="one") ./varenv11.sub: line 29: a: readonly variable +foo=abc a=z a=b a=z diff --git a/variables.c b/variables.c index 9d46b9a0..d08e337d 100644 --- a/variables.c +++ b/variables.c @@ -280,6 +280,7 @@ static SHELL_VAR *find_variable_nameref_context __P((SHELL_VAR *, VAR_CONTEXT *, static SHELL_VAR *find_variable_last_nameref_context __P((SHELL_VAR *, VAR_CONTEXT *, VAR_CONTEXT **)); static SHELL_VAR *bind_tempenv_variable __P((const char *, char *)); +static void push_posix_temp_var __P((PTR_T)); static void push_temp_var __P((PTR_T)); static void propagate_temp_var __P((PTR_T)); static void dispose_temporary_env __P((sh_free_func_t *)); @@ -4243,8 +4244,46 @@ find_tempenv_variable (name) char **tempvar_list; int tvlist_ind; +/* Take a variable from an assignment statement preceding a posix special + builtin (including `return') and create a global variable from it. This + is called from merge_temporary_env, which is only called when in posix + mode. */ +static void +push_posix_temp_var (data) + PTR_T data; +{ + SHELL_VAR *var, *v; + HASH_TABLE *binding_table; + + var = (SHELL_VAR *)data; + + binding_table = global_variables->table; + if (binding_table == 0) + binding_table = global_variables->table = hash_create (VARIABLES_HASH_BUCKETS); + + v = bind_variable_internal (var->name, value_cell (var), binding_table, 0, ASS_FORCE|ASS_NOLONGJMP); + + /* global variables are no longer temporary and don't need propagating. */ + var->attributes &= ~(att_tempvar|att_propagate); + if (v) + v->attributes |= var->attributes; + + if (find_special_var (var->name) >= 0) + tempvar_list[tvlist_ind++] = savestring (var->name); + + dispose_variable (var); +} + /* Push the variable described by (SHELL_VAR *)DATA down to the next - variable context from the temporary environment. */ + variable context from the temporary environment. This can be called + from one context: + 1. propagate_temp_var: which is called to propagate variables in + assignments like `var=value declare -x var' to the surrounding + scope. + + In this case, the variable should have the att_propagate flag set and + we can create variables in the current scope. +*/ static void push_temp_var (data) PTR_T data; @@ -4267,7 +4306,7 @@ push_temp_var (data) v = bind_variable_internal (var->name, value_cell (var), binding_table, 0, ASS_FORCE|ASS_NOLONGJMP); /* XXX - should we set the context here? It shouldn't matter because of how - assign_in_env works, but might want to check. */ + assign_in_env works, but we do it anyway. */ if (v) v->context = shell_variables->scope; @@ -4288,6 +4327,10 @@ push_temp_var (data) dispose_variable (var); } +/* Take a variable described by DATA and push it to the surrounding scope if + the PROPAGATE attribute is set. That gets set by push_temp_var if we are + taking a variable like `var=value declare -x var' and propagating it to + the enclosing scope. */ static void propagate_temp_var (data) PTR_T data; @@ -4351,12 +4394,15 @@ dispose_used_env_vars () } /* Take all of the shell variables in the temporary environment HASH_TABLE - and make shell variables from them at the current variable context. */ + and make shell variables from them at the current variable context. + Right now, this is only called in Posix mode to implement the historical + accident of creating global variables from assignment statements preceding + special builtins, but we check in case this acquires another caller later. */ void merge_temporary_env () { if (temporary_env) - dispose_temporary_env (push_temp_var); + dispose_temporary_env (posixly_correct ? push_posix_temp_var : push_temp_var); } void @@ -4859,6 +4905,16 @@ push_var_context (name, flags, tempvars) return (shell_variables = vc); } +/* This can be called from one of two code paths: + 1. pop_scope, which implements the posix rules for propagating variable + assignments preceding special builtins to the surrounding scope. + 2. pop_var_context, which is called from pop_context and implements the + posix rules for propagating variable assignments preceding function + calls to the surrounding scope. + + It takes variables out of a temporary environment hash table. We take the + variable in data +*/ static void push_func_var (data) PTR_T data; @@ -4978,11 +5034,7 @@ push_exported_var (data) propagated, bind it in the previous scope before disposing it. */ /* XXX - This isn't exactly right, because all tempenv variables have the export attribute set. */ -#if 0 - if (exported_p (var) || (var->attributes & att_propagate)) -#else if (tempvar_p (var) && exported_p (var) && (var->attributes & att_propagate)) -#endif { var->attributes &= ~att_tempvar; /* XXX */ v = bind_variable_internal (var->name, value_cell (var), shell_variables->table, 0, 0); @@ -5000,11 +5052,17 @@ push_exported_var (data) dispose_variable (var); } +/* This is called to propagate variables in the temporary environment of a + special builtin (if IS_SPECIAL != 0) or exported variables that are the + result of a builtin like `source' or `command' that can operate on the + variables in its temporary environment. In the first case, we call + push_func_var, which does the right thing (for now) */ void pop_scope (is_special) int is_special; { VAR_CONTEXT *vcxt, *ret; + int is_bltinenv; vcxt = shell_variables; if (vc_istempscope (vcxt) == 0) @@ -5012,6 +5070,7 @@ pop_scope (is_special) internal_error (_("pop_scope: head of shell_variables not a temporary environment scope")); return; } + is_bltinenv = vc_isbltnenv (vcxt); /* XXX - for later */ ret = vcxt->down; if (ret) diff --git a/variables.h b/variables.h index 50d4ccb2..bc1546d1 100644 --- a/variables.h +++ b/variables.h @@ -157,6 +157,7 @@ typedef struct _vlist { #define regen_p(var) ((((var)->attributes) & (att_regenerate))) #define tempvar_p(var) ((((var)->attributes) & (att_tempvar))) +#define propagate_p(var) ((((var)->attributes) & (att_propagate))) /* Variable names: lvalues */ #define name_cell(var) ((var)->name)