diff --git a/CWRU/CWRU.chlog b/CWRU/CWRU.chlog index 81082497..59f93ba9 100644 --- a/CWRU/CWRU.chlog +++ b/CWRU/CWRU.chlog @@ -3229,7 +3229,7 @@ doc/{bash.1,bashref.texi} 2/1 --- config-top.h - - DONT_REPORT_SIGPIPE: define, so non-interactive shells will no + - DONT_REPORT_SIGTERM: define, so non-interactive shells will no longer print termination messages for child processes killed by SIGTERM @@ -4186,3 +4186,54 @@ builtins/declare.def configure.ac - globasciiranges: RRI now on by default, must be turned off explicitly at configure time or runtime with `shopt -u globasciiranges' + + 8/14 + ---- +variables.c + - dispose_saved_dollar_vars: decrement stack pointer before looking + for saved positional parameters to dispose; stack pointer always + points to the first unused slot + + 8/15 + ---- +variables.c + - dollar_arg_stack: now a stack of struct saved_dollar_vars, which has + an array for the first ten (dollar_vars) and a WORD_LIST * for the + remaining (rest_of_args). Fixes performance issue with function calls + and large numbers of positional parameters raised by + Bize Ma + - {save,restore,free,free_saved}_dollar_vars: new functions to manage + dollar_vars and dollar_arg_stack members. Need to keep these in sync + with whatever remember_args does + - push_dollar_vars: use save_dollar_vars, which just copies pointers, + and directly assign rest_of_args, without copying the words, to the + dollar_arg_stack entry. Have to clear dollar_vars and rest_of_args + with the assumption that callers will call remember_args(args, 1) + immediately following + - pop_dollar_vars: free current positional parameters and restore old + ones from pointers saved in dollar_arg_stack, making sure to + invalidate any cached value for "$@" + - dispose_saved_dollar_vars: free saved pointers from current index + into dollar_arg_stack + +doc/{bash.1,bashref.texi} + - POSIXLY_CORRECT: make sure to note that bash makes sure this variable + is set when posix mode is enabled + + 8/17 + ---- +{jobs,nojobs}.c + - set_jobs_list_frozen: set jobs_list_frozen to a particular value. + Intended to save and restore the value around code sections instead + of unconditionally unfreezing it. + +jobs.h + - set_jobs_list_frozen: extern declaration + +execute_cmd.c + - execute_pipeline: if lastpipe is enabled, save and restore the + value of jobs_list_frozen using freeze_jobs_list/set_jobs_list_frozen + to avoid problems with race conditions and nested pipelines + causing jobs to be removed from the jobs table. Fixes savannah issue + https://savannah.gnu.org/support/index.php?109541 reported by + Björn Kautler diff --git a/MANIFEST b/MANIFEST index 6aec7404..2b267561 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1376,6 +1376,8 @@ tests/varenv11.sub f tests/varenv12.sub f tests/varenv13.sub f tests/varenv14.sub f +tests/varenv15.sub f +tests/varenv15.in f tests/version f tests/version.mini f tests/vredir.tests f diff --git a/aclocal.m4 b/aclocal.m4 index 6ea6f40f..6ed03e10 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -1307,7 +1307,7 @@ AC_CACHE_VAL(bash_cv_must_reinstall_sighandlers, typedef RETSIGTYPE sigfunc(); -int nsigint; +volatile int nsigint; #ifdef HAVE_POSIX_SIGNALS sigfunc * diff --git a/arrayfunc.c b/arrayfunc.c index 10b2b06a..e3700dd3 100644 --- a/arrayfunc.c +++ b/arrayfunc.c @@ -199,6 +199,8 @@ bind_array_var_internal (entry, ind, key, value, flags) FREE (newval); VUNSETATTR (entry, att_invisible); /* no longer invisible */ + + /* check mark_modified_variables if we ever want to export array vars */ return (entry); } diff --git a/configure b/configure index 682cafec..82e5ec36 100755 --- a/configure +++ b/configure @@ -15257,7 +15257,7 @@ else typedef RETSIGTYPE sigfunc(); -int nsigint; +volatile int nsigint; #ifdef HAVE_POSIX_SIGNALS sigfunc * diff --git a/doc/bash.1 b/doc/bash.1 index 9d1e5af2..9561ed87 100644 --- a/doc/bash.1 +++ b/doc/bash.1 @@ -2414,6 +2414,8 @@ running, \fBbash\fP enables \fIposix mode\fP, as if the command .if t \f(CWset -o posix\fP .if n \fIset -o posix\fP had been executed. +When the shell enters \fIposix mode\fP, it sets this variable if it was +not already set. .TP .B PROMPT_COMMAND If set, the value is executed as a command prior to issuing each primary diff --git a/doc/bashref.texi b/doc/bashref.texi index ba9e2b51..cb67c8a2 100644 --- a/doc/bashref.texi +++ b/doc/bashref.texi @@ -6189,7 +6189,9 @@ as if the command @code{set -o posix} @end example @noindent -had been executed. +had been executed. +When the shell enters @sc{posix} mode, it sets this variable if it was +not already set. @item PPID The process @sc{id} of the shell's parent process. This variable @@ -7528,6 +7530,9 @@ startup files. The following list is what's changed when `@sc{posix} mode' is in effect: @enumerate +@item +Bash ensures that the @env{POSIXLY_CORRECT} variable is set. + @item When a command in the hash table no longer exists, Bash will re-search @env{$PATH} to find the new location. This is also available with diff --git a/execute_cmd.c b/execute_cmd.c index 58d32c03..68b93006 100644 --- a/execute_cmd.c +++ b/execute_cmd.c @@ -2448,7 +2448,7 @@ execute_pipeline (command, asynchronous, pipe_in, pipe_out, fds_to_close) struct fd_bitmap *fds_to_close; { int prev, fildes[2], new_bitmap_size, dummyfd, ignore_return, exec_result; - int lstdin, lastpipe_flag, lastpipe_jid; + int lstdin, lastpipe_flag, lastpipe_jid, old_frozen; COMMAND *cmd; struct fd_bitmap *fd_bitmap; pid_t lastpid; @@ -2563,7 +2563,7 @@ execute_pipeline (command, asynchronous, pipe_in, pipe_out, fds_to_close) prev = NO_PIPE; add_unwind_protect (restore_stdin, lstdin); lastpipe_flag = 1; - freeze_jobs_list (); + old_frozen = freeze_jobs_list (); lastpipe_jid = stop_pipeline (0, (COMMAND *)NULL); /* XXX */ add_unwind_protect (lastpipe_cleanup, lastpipe_jid); } @@ -2611,9 +2611,9 @@ execute_pipeline (command, asynchronous, pipe_in, pipe_out, fds_to_close) else if (pipefail_opt) exec_result = exec_result | lstdin; /* XXX */ /* otherwise we use exec_result */ - #endif - unfreeze_jobs_list (); + + set_jobs_list_frozen (old_frozen); } discard_unwind_frame ("lastpipe-exec"); diff --git a/jobs.c b/jobs.c index dc322b1b..f517a248 100644 --- a/jobs.c +++ b/jobs.c @@ -4771,6 +4771,13 @@ unfreeze_jobs_list () jobs_list_frozen = 0; } +void +set_jobs_list_frozen (s) + int s; +{ + jobs_list_frozen = s; +} + /* Allow or disallow job control to take place. Returns the old value of job_control. */ int diff --git a/jobs.h b/jobs.h index 4eca6260..6ebaf4de 100644 --- a/jobs.h +++ b/jobs.h @@ -259,7 +259,8 @@ extern int give_terminal_to __P((pid_t, int)); extern void run_sigchld_trap __P((int)); extern int freeze_jobs_list __P((void)); -extern void unfreeze_jobs_list __P((void)); +extern void unfreeeze_jobs_list __P((void)); +extern void set_jobs_list_frozen __P((int)); extern int set_job_control __P((int)); extern void without_job_control __P((void)); extern void end_job_control __P((void)); diff --git a/lib/sh/snprintf.c b/lib/sh/snprintf.c index 87ca2173..6e5892ee 100644 --- a/lib/sh/snprintf.c +++ b/lib/sh/snprintf.c @@ -142,9 +142,11 @@ extern char *fmtullong __P((unsigned long long int, int, char *, size_t, int)); 302 / 1000 is log10 (2) rounded up; add one for integer division truncation; add one more for a minus sign if t is signed. */ +#ifndef INT_STRLEN_BOUND #define INT_STRLEN_BOUND(t) \ ((sizeof (t) * CHAR_BIT - TYPE_SIGNED (t)) * 302 / 1000 \ + 1 + TYPE_SIGNED (t)) +#endif /* conversion flags */ #define PF_ALTFORM 0x00001 /* # */ diff --git a/nojobs.c b/nojobs.c index 472624b9..2201a29a 100644 --- a/nojobs.c +++ b/nojobs.c @@ -1037,6 +1037,12 @@ unfreeze_jobs_list () { } +void +set_jobs_list_frozen (s) + int s; +{ +} + int count_all_jobs () { diff --git a/tests/varenv.right b/tests/varenv.right index c2f00848..4e8c0d16 100644 --- a/tests/varenv.right +++ b/tests/varenv.right @@ -177,6 +177,36 @@ declare -a a=([0]="X" [1]="Y") declare -a s=([0]="X" [1]="Y") declare -a a=([0]="XY") declare -a s=([0]="XY") +f: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 +f1: after: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 +done: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 +f3:1 +f3:2 +f3:3 +f3:4 +f3:5 +f3:6 +f3:7 +f3:8 +f3:9 +f3:10 +f3:11 +f3:12 +f3:13 +f3:14 +f3:15 +f3:16 +f3:17 +f3:18 +f3:19 +f3:20 +before source: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 +varenv15.in: before set: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 +varenv15.in: after set: a b c d e f g h i j k l m n o p q r s t u v w x y z +after source 1: a b c d e f g h i j k l m n o p q r s t u v w x y z +varenv15.in: before set: one two three four five six seven eight nine ten +varenv15.in: after set: a b c d e f g h i j k l m n o p q r s t u v w x y z +after source 2: a b c d e f g h i j k l m n o p q r s t u v w x y z a=z a=b a=z diff --git a/tests/varenv.tests b/tests/varenv.tests index 52d23fdd..34b85596 100644 --- a/tests/varenv.tests +++ b/tests/varenv.tests @@ -240,5 +240,7 @@ ${THIS_SH} ./varenv13.sub # localvar_inherit ${THIS_SH} ./varenv14.sub +${THIS_SH} ./varenv15.sub + # make sure variable scoping is done right tt() { typeset a=b;echo a=$a; };a=z;echo a=$a;tt;echo a=$a diff --git a/tests/varenv15.in b/tests/varenv15.in new file mode 100644 index 00000000..e635b12a --- /dev/null +++ b/tests/varenv15.in @@ -0,0 +1,3 @@ +echo varenv15.in: before set: "$@" +set -- a b c d e f g h i j k l m n o p q r s t u v w x y z +echo varenv15.in: after set: "$@" diff --git a/tests/varenv15.sub b/tests/varenv15.sub new file mode 100644 index 00000000..52c8a940 --- /dev/null +++ b/tests/varenv15.sub @@ -0,0 +1,38 @@ +# check saving and restoring positional parameters around function calls + +f() +{ + echo $FUNCNAME: "$@" +} + +f1() +{ + f {1..50} + echo $FUNCNAME: after: $@ +} + +set -- {1..100} + +f1 {1..20} +echo done: $@ + +f3() +{ + echo $FUNCNAME:$1 + shift + if [ $# -le 0 ]; then + return + fi + f3 "$@" +} + +f3 {1..20} + +# now let's try source with and without positional parameters + +set -- {1..20} +echo before source: "$@" +. ./varenv15.in +echo after source 1: "$@" +. ./varenv15.in one two three four five six seven eight nine ten +echo after source 2: "$@" diff --git a/variables.c b/variables.c index 8336d073..00872d64 100644 --- a/variables.c +++ b/variables.c @@ -5290,10 +5290,64 @@ pop_scope (is_special) /* */ /* **************************************************************** */ -static WORD_LIST **dollar_arg_stack = (WORD_LIST **)NULL; +struct saved_dollar_vars { + char **first_ten; + WORD_LIST *rest; +}; + +static struct saved_dollar_vars *dollar_arg_stack = (struct saved_dollar_vars *)NULL; static int dollar_arg_stack_slots; static int dollar_arg_stack_index; +/* Functions to manipulate dollar_vars array. Need to keep these in sync with + whatever remember_args() does. */ +static char ** +save_dollar_vars () +{ + char **ret; + int i; + + ret = strvec_create (10); + for (i = 1; i < 10; i++) + { + ret[i] = dollar_vars[i]; + dollar_vars[i] = (char *)NULL; + } + return ret; +} + +static void +restore_dollar_vars (args) + char **args; +{ + int i; + + for (i = 1; i < 10; i++) + dollar_vars[i] = args[i]; +} + +static void +free_dollar_vars () +{ + int i; + + for (i = 1; i < 10; i++) + { + FREE (dollar_vars[i]); + dollar_vars[i] = (char *)NULL; + } +} + +static void +free_saved_dollar_vars (args) + char **args; +{ + int i; + + for (i = 1; i < 10; i++) + FREE (args[i]); +} + /* XXX - should always be followed by remember_args () */ void push_context (name, is_subshell, tempvars) @@ -5325,35 +5379,53 @@ push_dollar_vars () { if (dollar_arg_stack_index + 2 > dollar_arg_stack_slots) { - dollar_arg_stack = (WORD_LIST **) + dollar_arg_stack = (struct saved_dollar_vars *) xrealloc (dollar_arg_stack, (dollar_arg_stack_slots += 10) - * sizeof (WORD_LIST *)); + * sizeof (struct saved_dollar_vars)); } - dollar_arg_stack[dollar_arg_stack_index++] = list_rest_of_args (); - dollar_arg_stack[dollar_arg_stack_index] = (WORD_LIST *)NULL; + + dollar_arg_stack[dollar_arg_stack_index].first_ten = save_dollar_vars (); + dollar_arg_stack[dollar_arg_stack_index++].rest = rest_of_args; + rest_of_args = (WORD_LIST *)NULL; + + dollar_arg_stack[dollar_arg_stack_index].first_ten = (char **)NULL; + dollar_arg_stack[dollar_arg_stack_index].rest = (WORD_LIST *)NULL; } /* Restore the positional parameters from our stack. */ void pop_dollar_vars () { - if (!dollar_arg_stack || dollar_arg_stack_index == 0) + if (dollar_arg_stack == 0 || dollar_arg_stack_index == 0) return; - remember_args (dollar_arg_stack[--dollar_arg_stack_index], 1); - dispose_words (dollar_arg_stack[dollar_arg_stack_index]); - dollar_arg_stack[dollar_arg_stack_index] = (WORD_LIST *)NULL; + /* Do what remember_args (xxx, 1) would have done. */ + free_dollar_vars (); + dispose_words (rest_of_args); + + rest_of_args = dollar_arg_stack[--dollar_arg_stack_index].rest; + restore_dollar_vars (dollar_arg_stack[dollar_arg_stack_index].first_ten); + free (dollar_arg_stack[dollar_arg_stack_index].first_ten); + + dollar_arg_stack[dollar_arg_stack_index].first_ten = (char **)NULL; + dollar_arg_stack[dollar_arg_stack_index].rest = (WORD_LIST *)NULL; + set_dollar_vars_unchanged (); + invalidate_cached_quoted_dollar_at (); } void dispose_saved_dollar_vars () { - if (!dollar_arg_stack || dollar_arg_stack_index == 0) + if (dollar_arg_stack == 0 || dollar_arg_stack_index == 0) return; - dispose_words (dollar_arg_stack[dollar_arg_stack_index]); - dollar_arg_stack[dollar_arg_stack_index] = (WORD_LIST *)NULL; + dispose_words (dollar_arg_stack[--dollar_arg_stack_index].rest); + free_saved_dollar_vars (dollar_arg_stack[dollar_arg_stack_index].first_ten); + free (dollar_arg_stack[dollar_arg_stack_index].first_ten); + + dollar_arg_stack[dollar_arg_stack_index].first_ten = (char **)NULL; + dollar_arg_stack[dollar_arg_stack_index].rest = (WORD_LIST *)NULL; } /* Initialize BASH_ARGV and BASH_ARGC after turning on extdebug after the