From: Chet Ramey Date: Fri, 22 Feb 2019 14:14:00 +0000 (-0500) Subject: commit bash-20190220 snapshot X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=9e48f856544da2d2cc95600f487e5b5bcefa0d85;p=thirdparty%2Fbash.git commit bash-20190220 snapshot --- diff --git a/CWRU/CWRU.chlog b/CWRU/CWRU.chlog index 54e267c93..4442a20d5 100644 --- a/CWRU/CWRU.chlog +++ b/CWRU/CWRU.chlog @@ -5317,3 +5317,44 @@ jobs.c an interactive shell reported by Grisha Levit + 2/19 + ---- + +jobs.c + - end_job_control: if the setpgid(0, ...) succeeds, reset the value of + shell_pgrp. Fixes pgrp mismatch after failed exec in an interactive + login shell reported by Grisha Levit + + 2/20 + ---- +bashhist.c + - pre_process_line: save history_length before calling history_expand, + and after possibly decrementing history_length, just restore the old + value instead of incrementing it. Fixes bug reported by + Michael Albinus + - bash_add_history: don't bother calling really_add_history if the + history is stifled and the max number of entries is 0 + +aclocal.m4,configure.ac,m4/*.m4 + - replace the old set of gettext m4 macros with the latest m4 files + from the gnulib and gettext distributions + + 2/21 + ---- +builtins/cd.def + - bindpwd: initialize canon_failed to 0 to prevent `cd -e' from always + failing + +command.h + - W_EXPANDRHS: new flag, set when expanding WORD in ${paramOPword} + +subst.c + - expand_string_for_rhs: set W_EXPANDRHS in word to be expanded + +subst.c + - expand_word_internal: when encountering a single or double quoted + string that expands to nothing, add a CTLNUL if the W_EXPANDRHS + flag is set and the word isn't quoted, indicating that the word + will eventually be split and we need to preserve the null to + produce an empty word. From a discussion on bug-bash started by + sunnycemetery@gmail.com diff --git a/MANIFEST b/MANIFEST index cf957d3e1..5c9a37bbb 100644 --- a/MANIFEST +++ b/MANIFEST @@ -502,6 +502,7 @@ m4/nls.m4 f m4/po.m4 f m4/printf-posix.m4 f m4/progtest.m4 f +m4/pthread_rwlock_rdlock.m4 f m4/size_max.m4 f m4/stdint_h.m4 f m4/threadlib.m4 f diff --git a/bashhist.c b/bashhist.c index 7912cce31..f7f168ff2 100644 --- a/bashhist.c +++ b/bashhist.c @@ -560,15 +560,18 @@ pre_process_line (line, print_changes, addit) add that line to the history if ADDIT is non-zero. */ if (!history_expansion_inhibited && history_expansion && history_expansion_p (line)) { + int old_len; + /* If we are expanding the second or later line of a multi-line command, decrease history_length so references to history expansions in these lines refer to the previous history entry and not the current command. */ + old_len = history_length; if (history_length > 0 && command_oriented_history && current_command_first_line_saved && current_command_line_count > 1) history_length--; expanded = history_expand (line, &history_value); if (history_length >= 0 && command_oriented_history && current_command_first_line_saved && current_command_line_count > 1) - history_length++; + history_length = old_len; if (expanded) { @@ -908,6 +911,9 @@ bash_add_history (line) } } + if (add_it && history_is_stifled() && history_length == 0 && history_length == history_max_entries) + add_it = 0; + if (add_it) really_add_history (line); diff --git a/builtins/cd.def b/builtins/cd.def index fe75b57f1..2e3fcd820 100644 --- a/builtins/cd.def +++ b/builtins/cd.def @@ -149,6 +149,7 @@ bindpwd (no_symlinks) #undef tcwd /* If canonicalization fails, reset dirname to the_current_working_directory */ + canon_failed = 0; if (dirname == 0) { canon_failed = 1; diff --git a/command.h b/command.h index b9e9b6693..886aa17dc 100644 --- a/command.h +++ b/command.h @@ -87,7 +87,7 @@ enum command_type { cm_for, cm_case, cm_while, cm_if, cm_simple, cm_select, #define W_ASSIGNRHS 0x000800 /* Word is rhs of an assignment statement */ #define W_NOTILDE 0x001000 /* Don't perform tilde expansion on this word */ #define W_ITILDE 0x002000 /* Internal flag for word expansion */ -#define W_NOEXPAND 0x004000 /* Don't expand at all -- do quote removal */ +#define W_EXPANDRHS 0x004000 /* Expanding word in ${paramOPword} */ #define W_COMPASSIGN 0x008000 /* Compound assignment */ #define W_ASSNBLTIN 0x010000 /* word is a builtin command that takes assignments */ #define W_ASSIGNARG 0x020000 /* word is assignment argument to command */ @@ -111,6 +111,7 @@ enum command_type { cm_for, cm_case, cm_while, cm_if, cm_simple, cm_select, #define PF_NOSPLIT2 0x04 /* same as W_NOSPLIT2 */ #define PF_ASSIGNRHS 0x08 /* same as W_ASSIGNRHS */ #define PF_COMPLETE 0x10 /* same as W_COMPLETE, sets SX_COMPLETE */ +#define PF_EXPANDRHS 0x20 /* same as W_EXPANDRHS */ /* Possible values for subshell_environment */ #define SUBSHELL_ASYNC 0x01 /* subshell caused by `command &' */ diff --git a/configure b/configure index db701ff70..f1b6e0d28 100755 --- a/configure +++ b/configure @@ -1,5 +1,5 @@ #! /bin/sh -# From configure.ac for Bash 5.0, version 5.007. +# From configure.ac for Bash 5.0, version 5.008. # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.69 for bash 5.0-maint. # @@ -6242,6 +6242,11 @@ fi +# pthread_rwlock_rdlock.m4 serial 2 + + + + # size_max.m4 serial 11 @@ -9642,7 +9647,155 @@ $as_echo "#define HAVE_PTHREAD_RWLOCK 1" >>confdefs.h fi if $has_rwlock; then - gl_PTHREAD_RWLOCK_RDLOCK_PREFER_WRITER + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether pthread_rwlock_rdlock prefers a writer to a reader" >&5 +$as_echo_n "checking whether pthread_rwlock_rdlock prefers a writer to a reader... " >&6; } +if ${gl_cv_pthread_rwlock_rdlock_prefer_writer+:} false; then : + $as_echo_n "(cached) " >&6 +else + save_LIBS="$LIBS" + LIBS="$LIBS $LIBMULTITHREAD" + if test "$cross_compiling" = yes; then : + gl_cv_pthread_rwlock_rdlock_prefer_writer="guessing yes" +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include +#include +#include + +#define SUCCEED() exit (0) +#define FAILURE() exit (1) +#define UNEXPECTED(n) (exit (10 + (n))) + +/* The main thread creates the waiting writer and the requesting reader threads + in the default way; this guarantees that they have the same priority. + We can reuse the main thread as first reader thread. */ + +static pthread_rwlock_t lock; +static pthread_t reader1; +static pthread_t writer; +static pthread_t reader2; +static pthread_t timer; +/* Used to pass control from writer to reader2 and from reader2 to timer, + as in a relay race. + Passing control from one running thread to another running thread + is most likely faster than to create the second thread. */ +static pthread_mutex_t baton; + +static void * +timer_func (void *ignored) +{ + /* Step 13 (can be before or after step 12): + The timer thread takes the baton, then waits a moment to make sure + it can tell whether the second reader thread is blocked at step 12. */ + if (pthread_mutex_lock (&baton)) + UNEXPECTED (13); + usleep (100000); + /* By the time we get here, it's clear that the second reader thread is + blocked at step 12. This is the desired behaviour. */ + SUCCEED (); +} + +static void * +reader2_func (void *ignored) +{ + int err; + + /* Step 8 (can be before or after step 7): + The second reader thread takes the baton, then waits a moment to make sure + the writer thread has reached step 7. */ + if (pthread_mutex_lock (&baton)) + UNEXPECTED (8); + usleep (100000); + /* Step 9: The second reader thread requests the lock. */ + err = pthread_rwlock_tryrdlock (&lock); + if (err == 0) + FAILURE (); + else if (err != EBUSY) + UNEXPECTED (9); + /* Step 10: Launch a timer, to test whether the next call blocks. */ + if (pthread_create (&timer, NULL, timer_func, NULL)) + UNEXPECTED (10); + /* Step 11: Release the baton. */ + if (pthread_mutex_unlock (&baton)) + UNEXPECTED (11); + /* Step 12: The second reader thread requests the lock. */ + err = pthread_rwlock_rdlock (&lock); + if (err == 0) + FAILURE (); + else + UNEXPECTED (12); +} + +static void * +writer_func (void *ignored) +{ + /* Step 4: Take the baton, so that the second reader thread does not go ahead + too early. */ + if (pthread_mutex_lock (&baton)) + UNEXPECTED (4); + /* Step 5: Create the second reader thread. */ + if (pthread_create (&reader2, NULL, reader2_func, NULL)) + UNEXPECTED (5); + /* Step 6: Release the baton. */ + if (pthread_mutex_unlock (&baton)) + UNEXPECTED (6); + /* Step 7: The writer thread requests the lock. */ + if (pthread_rwlock_wrlock (&lock)) + UNEXPECTED (7); + return NULL; +} + +int +main () +{ + reader1 = pthread_self (); + + /* Step 1: The main thread initializes the lock and the baton. */ + if (pthread_rwlock_init (&lock, NULL)) + UNEXPECTED (1); + if (pthread_mutex_init (&baton, NULL)) + UNEXPECTED (1); + /* Step 2: The main thread acquires the lock as a reader. */ + if (pthread_rwlock_rdlock (&lock)) + UNEXPECTED (2); + /* Step 3: Create the writer thread. */ + if (pthread_create (&writer, NULL, writer_func, NULL)) + UNEXPECTED (3); + /* Job done. Go to sleep. */ + for (;;) + { + sleep (1); + } +} + +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + gl_cv_pthread_rwlock_rdlock_prefer_writer=yes +else + gl_cv_pthread_rwlock_rdlock_prefer_writer=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + LIBS="$save_LIBS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_pthread_rwlock_rdlock_prefer_writer" >&5 +$as_echo "$gl_cv_pthread_rwlock_rdlock_prefer_writer" >&6; } + case "$gl_cv_pthread_rwlock_rdlock_prefer_writer" in + *yes) + +$as_echo "#define HAVE_PTHREAD_RWLOCK_RDLOCK_PREFER_WRITER 1" >>confdefs.h + + ;; + esac + fi # glibc defines PTHREAD_MUTEX_RECURSIVE as enum, not as a macro. cat confdefs.h - <<_ACEOF >conftest.$ac_ext diff --git a/configure.ac b/configure.ac index ab8bc23f5..9eecf8786 100644 --- a/configure.ac +++ b/configure.ac @@ -21,7 +21,7 @@ dnl Process this file with autoconf to produce a configure script. # You should have received a copy of the GNU General Public License # along with this program. If not, see . -AC_REVISION([for Bash 5.0, version 5.007])dnl +AC_REVISION([for Bash 5.0, version 5.008])dnl define(bashvers, 5.0) define(relstatus, maint) @@ -712,6 +712,7 @@ m4_include([m4/nls.m4]) m4_include([m4/po.m4]) m4_include([m4/printf-posix.m4]) m4_include([m4/progtest.m4]) +m4_include([m4/pthread_rwlock_rdlock.m4]) m4_include([m4/size_max.m4]) m4_include([m4/stdint_h.m4]) m4_include([m4/threadlib.m4]) diff --git a/doc/bashref.texi b/doc/bashref.texi index a7198fa58..89aa6cb61 100644 --- a/doc/bashref.texi +++ b/doc/bashref.texi @@ -7188,7 +7188,7 @@ is also accepted; the @var{subscript} is ignored. @noindent Associative arrays are created using @example -declare -A @var{name}. +declare -A @var{name} @end example Attributes may be diff --git a/jobs.c b/jobs.c index a23585b19..a3905afba 100644 --- a/jobs.c +++ b/jobs.c @@ -4844,8 +4844,8 @@ end_job_control () if (original_pgrp >= 0 && terminal_pgrp != original_pgrp) give_terminal_to (original_pgrp, 1); - if (original_pgrp >= 0) - setpgid (0, original_pgrp); + if (original_pgrp >= 0 && setpgid (0, original_pgrp) == 0) + shell_pgrp = original_pgrp; } /* Restart job control by closing shell tty and reinitializing. This is diff --git a/m4/pthread_rwlock_rdlock.m4 b/m4/pthread_rwlock_rdlock.m4 new file mode 100644 index 000000000..3c1d64566 --- /dev/null +++ b/m4/pthread_rwlock_rdlock.m4 @@ -0,0 +1,165 @@ +# pthread_rwlock_rdlock.m4 serial 2 +dnl Copyright (C) 2017-2019 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Bruno Haible. +dnl Inspired by +dnl https://github.com/linux-test-project/ltp/blob/master/testcases/open_posix_testsuite/conformance/interfaces/pthread_rwlock_rdlock/2-2.c +dnl by Intel Corporation. + +dnl Test whether in a situation where +dnl - an rwlock is taken by a reader and has a writer waiting, +dnl - an additional reader requests the lock, +dnl - the waiting writer and the requesting reader threads have the same +dnl priority, +dnl the requesting reader thread gets blocked, so that at some point the +dnl waiting writer can acquire the lock. +dnl Without such a guarantee, when there a N readers and each of the readers +dnl spends more than 1/Nth of the time with the lock held, there is a high +dnl probability that the waiting writer will not get the lock in a given finite +dnl time, a phenomenon called "writer starvation". +dnl Without such a guarantee, applications have a hard time avoiding writer +dnl starvation. +dnl +dnl POSIX:2017 makes this requirement only for implementations that support TPS +dnl (Thread Priority Scheduling) and only for the scheduling policies SCHED_FIFO +dnl and SCHED_RR, see +dnl http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_rwlock_rdlock.html +dnl but this test verifies the guarantee regardless of TPS and regardless of +dnl scheduling policy. +dnl Glibc currently does not provide this guarantee, see +dnl https://sourceware.org/bugzilla/show_bug.cgi?id=13701 +AC_DEFUN([gl_PTHREAD_RWLOCK_RDLOCK_PREFER_WRITER], +[ + AC_REQUIRE([gl_THREADLIB_EARLY]) + AC_CACHE_CHECK([whether pthread_rwlock_rdlock prefers a writer to a reader], + [gl_cv_pthread_rwlock_rdlock_prefer_writer], + [save_LIBS="$LIBS" + LIBS="$LIBS $LIBMULTITHREAD" + AC_RUN_IFELSE( + [AC_LANG_SOURCE([[ +#include +#include +#include +#include + +#define SUCCEED() exit (0) +#define FAILURE() exit (1) +#define UNEXPECTED(n) (exit (10 + (n))) + +/* The main thread creates the waiting writer and the requesting reader threads + in the default way; this guarantees that they have the same priority. + We can reuse the main thread as first reader thread. */ + +static pthread_rwlock_t lock; +static pthread_t reader1; +static pthread_t writer; +static pthread_t reader2; +static pthread_t timer; +/* Used to pass control from writer to reader2 and from reader2 to timer, + as in a relay race. + Passing control from one running thread to another running thread + is most likely faster than to create the second thread. */ +static pthread_mutex_t baton; + +static void * +timer_func (void *ignored) +{ + /* Step 13 (can be before or after step 12): + The timer thread takes the baton, then waits a moment to make sure + it can tell whether the second reader thread is blocked at step 12. */ + if (pthread_mutex_lock (&baton)) + UNEXPECTED (13); + usleep (100000); + /* By the time we get here, it's clear that the second reader thread is + blocked at step 12. This is the desired behaviour. */ + SUCCEED (); +} + +static void * +reader2_func (void *ignored) +{ + int err; + + /* Step 8 (can be before or after step 7): + The second reader thread takes the baton, then waits a moment to make sure + the writer thread has reached step 7. */ + if (pthread_mutex_lock (&baton)) + UNEXPECTED (8); + usleep (100000); + /* Step 9: The second reader thread requests the lock. */ + err = pthread_rwlock_tryrdlock (&lock); + if (err == 0) + FAILURE (); + else if (err != EBUSY) + UNEXPECTED (9); + /* Step 10: Launch a timer, to test whether the next call blocks. */ + if (pthread_create (&timer, NULL, timer_func, NULL)) + UNEXPECTED (10); + /* Step 11: Release the baton. */ + if (pthread_mutex_unlock (&baton)) + UNEXPECTED (11); + /* Step 12: The second reader thread requests the lock. */ + err = pthread_rwlock_rdlock (&lock); + if (err == 0) + FAILURE (); + else + UNEXPECTED (12); +} + +static void * +writer_func (void *ignored) +{ + /* Step 4: Take the baton, so that the second reader thread does not go ahead + too early. */ + if (pthread_mutex_lock (&baton)) + UNEXPECTED (4); + /* Step 5: Create the second reader thread. */ + if (pthread_create (&reader2, NULL, reader2_func, NULL)) + UNEXPECTED (5); + /* Step 6: Release the baton. */ + if (pthread_mutex_unlock (&baton)) + UNEXPECTED (6); + /* Step 7: The writer thread requests the lock. */ + if (pthread_rwlock_wrlock (&lock)) + UNEXPECTED (7); + return NULL; +} + +int +main () +{ + reader1 = pthread_self (); + + /* Step 1: The main thread initializes the lock and the baton. */ + if (pthread_rwlock_init (&lock, NULL)) + UNEXPECTED (1); + if (pthread_mutex_init (&baton, NULL)) + UNEXPECTED (1); + /* Step 2: The main thread acquires the lock as a reader. */ + if (pthread_rwlock_rdlock (&lock)) + UNEXPECTED (2); + /* Step 3: Create the writer thread. */ + if (pthread_create (&writer, NULL, writer_func, NULL)) + UNEXPECTED (3); + /* Job done. Go to sleep. */ + for (;;) + { + sleep (1); + } +} +]])], + [gl_cv_pthread_rwlock_rdlock_prefer_writer=yes], + [gl_cv_pthread_rwlock_rdlock_prefer_writer=no], + [gl_cv_pthread_rwlock_rdlock_prefer_writer="guessing yes"]) + LIBS="$save_LIBS" + ]) + case "$gl_cv_pthread_rwlock_rdlock_prefer_writer" in + *yes) + AC_DEFINE([HAVE_PTHREAD_RWLOCK_RDLOCK_PREFER_WRITER], [1], + [Define if the 'pthread_rwlock_rdlock' function prefers a writer to a reader.]) + ;; + esac +]) diff --git a/subst.c b/subst.c index f9d34ca7a..ca6634a9e 100644 --- a/subst.c +++ b/subst.c @@ -428,10 +428,10 @@ dump_word_flags (flags) f &= ~W_COMPASSIGN; fprintf (stderr, "W_COMPASSIGN%s", f ? "|" : ""); } - if (f & W_NOEXPAND) + if (f & W_EXPANDRHS) { - f &= ~W_NOEXPAND; - fprintf (stderr, "W_NOEXPAND%s", f ? "|" : ""); + f &= ~W_EXPANDRHS; + fprintf (stderr, "W_EXPANDRHS%s", f ? "|" : ""); } if (f & W_ITILDE) { @@ -3899,7 +3899,8 @@ expand_string_for_rhs (string, quoted, op, pflags, dollar_at_p, expanded_p) in Posix bug 1129 */ old_nosplit = expand_no_split_dollar_star; expand_no_split_dollar_star = (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) || op == '=' || ifs_is_null == 0; /* XXX - was 1 */ - td.flags = W_NOSPLIT2; /* no splitting, remove "" and '' */ + td.flags = W_EXPANDRHS; /* expanding RHS of ${paramOPword */ + td.flags |= W_NOSPLIT2; /* no splitting, remove "" and '' */ if (pflags & PF_ASSIGNRHS) /* pass through */ td.flags |= W_ASSIGNRHS; if (op == '=') @@ -10296,6 +10297,13 @@ add_twochars: this is when we are going to be performing word splitting, since we have to preserve a null argument if the next character will cause word splitting. */ + if (temp == 0 && quoted_state == PARTIALLY_QUOTED && quoted == 0 && (word->flags & W_NOSPLIT) == 0 && (word->flags & W_EXPANDRHS)) + { + c = CTLNUL; + sindex--; + had_quoted_null = 1; + goto add_character; + } if (temp == 0 && quoted_state == PARTIALLY_QUOTED && (word->flags & (W_NOSPLIT|W_NOSPLIT2))) continue; @@ -10347,7 +10355,14 @@ add_twochars: /* We do not want to add quoted nulls to strings that are only partially quoted; such nulls are discarded. See above for the exception, which is when the string is going to be split. - Posix interp 888 */ + Posix interp 888/1129 */ + if (temp == 0 && quoted_state == PARTIALLY_QUOTED && quoted == 0 && (word->flags & W_NOSPLIT) == 0 && (word->flags & W_EXPANDRHS)) + { + c = CTLNUL; + sindex--; + goto add_character; + } + if (temp == 0 && (quoted_state == PARTIALLY_QUOTED) && (word->flags & (W_NOSPLIT|W_NOSPLIT2))) continue; @@ -10478,8 +10493,6 @@ finished_with_string: tword->flags |= W_NOGLOB; /* XXX */ if (word->flags & W_NOBRACE) tword->flags |= W_NOBRACE; /* XXX */ - if (word->flags & W_NOEXPAND) - tword->flags |= W_NOEXPAND; /* XXX */ if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) tword->flags |= W_QUOTED; list = make_word_list (tword, (WORD_LIST *)NULL); @@ -10577,8 +10590,6 @@ set_word_flags: tword->flags |= W_NOGLOB; if (word->flags & W_NOBRACE) tword->flags |= W_NOBRACE; - if (word->flags & W_NOEXPAND) - tword->flags |= W_NOEXPAND; list = make_word_list (tword, (WORD_LIST *)NULL); } } diff --git a/tests/dollar.right b/tests/dollar.right index d72361f9d..746ce16b5 100644 --- a/tests/dollar.right +++ b/tests/dollar.right @@ -226,6 +226,7 @@ null fields in rhs null string with unquoted $@ argv[1] = <> null string with quoted $@ +argv[1] = <> assignment argv[1] = <> variable diff --git a/tests/quote.right b/tests/quote.right index e4eb9bb95..174384aa1 100644 --- a/tests/quote.right +++ b/tests/quote.right @@ -94,23 +94,29 @@ argv[1] = <> argv[1] = <> argv[1] = <> argv[1] = <> +argv[2] = <> argv[1] = <> +argv[2] = <> argv[1] = <> ===== argv[1] = <> argv[1] = <> argv[1] = <> argv[1] = <> +argv[2] = <> argv[1] = <> argv[1] = <> argv[1] = <> +argv[2] = <> ===== argv[1] = <> argv[1] = <> argv[1] = <> argv[1] = <> argv[1] = <> +argv[2] = <> argv[1] = <> +argv[2] = <> argv[1] = <> ===== argv[1] = <> @@ -118,5 +124,7 @@ argv[1] = <> argv[1] = <> argv[1] = <> argv[1] = <> +argv[2] = <> argv[1] = <> +argv[2] = <> argv[1] = <>