From: Chet Ramey Date: Sun, 14 Jan 2024 20:38:36 +0000 (-0500) Subject: unconditionally define PGRP_PIPE; fix wait in funsubs; fix REPLY as nameref in varsub... X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=f2fdb5e31317bf5199814ae9866debe1c20cd3a4;p=thirdparty%2Fbash.git unconditionally define PGRP_PIPE; fix wait in funsubs; fix REPLY as nameref in varsub; fix crash with parse errors in compound assignments --- diff --git a/CWRU/CWRU.chlog b/CWRU/CWRU.chlog index 6fd26ca01..f61d572ad 100644 --- a/CWRU/CWRU.chlog +++ b/CWRU/CWRU.chlog @@ -8260,3 +8260,47 @@ parse.y reset_parser already freed it and we don't want to try and restore it in restore_parser_state. From a report by Nathan Mills + + 1/10 + ---- +builtins/hash.def, builtins/ulimit.def + - add some calls to sh_chkwrite where there is builtin output + +lib/sh/eaccess.c + - sh_stat: use strcpy/strcpy when constructing pbuf instead of + strcpy/strcat + +lib/sh/tmpfile.c + - sh_mktmpname,sh_mktmpfd,sh_mktmpdir: use snprintf (filename, PATH_MAX, ...) + instead of sprintf (filename, ...) + + 1/11 + ---- +configure.ac + - unconditionally AC_DEFINE(PGRP_PIPE), to prevent the problem with a + pipeline and a DEBUG trap containing an external command described + in https://lists.gnu.org/archive/html/bug-bash/2024-01/msg00037.html + + 1/12 + ---- +jobs.c + - wait_for_any_job: if we're executing a funsub/varsub, do the wait + even if the jobs list is frozen, but don't remove the job from the + table or change its notification status + Report from Oguz + +subst.c + - uw_unbind_variable: unset the first instance of the named variable, + don't follow namerefs. This is for REPLY in a varsub if it's made + a nameref. + Report from Oguz + +shell.c + - main: call compat_init() so the linker drags in the old compatibility + functions from lib/sh/compat.c. Primarily for use by existing loadable + builtins + +parse.y + - parse_compound_assignment: handle error case (wl == &parse_string_error) + before restoring the parser state from ps + Report from Grisha Levit diff --git a/builtins/hash.def b/builtins/hash.def index 34460afc4..dd0bf76f4 100644 --- a/builtins/hash.def +++ b/builtins/hash.def @@ -123,7 +123,7 @@ hash_builtin (WORD_LIST *list) if (list == 0 && (delete || list_targets)) { sh_needarg (delete ? "-d" : "-t"); - return (EXECUTION_FAILURE); + return (sh_chkwrite (EXECUTION_FAILURE)); } /* It's an error to specify a pathname to hash to, but no name to hash. */ @@ -299,5 +299,5 @@ list_hashed_filename_targets (WORD_LIST *list, int fmt) free (target); } - return (all_found ? EXECUTION_SUCCESS : EXECUTION_FAILURE); + return (sh_chkwrite (all_found ? EXECUTION_SUCCESS : EXECUTION_FAILURE)); } diff --git a/builtins/ulimit.def b/builtins/ulimit.def index fa527ad78..64c31e148 100644 --- a/builtins/ulimit.def +++ b/builtins/ulimit.def @@ -437,7 +437,7 @@ ulimit_builtin (WORD_LIST *list) if (ulimit_internal (cmdlist[c].cmd, cmdlist[c].arg, mode, ncmd > 1) == EXECUTION_FAILURE) return (EXECUTION_FAILURE); - return (EXECUTION_SUCCESS); + return (sh_chkwrite (EXECUTION_SUCCESS)); } static int diff --git a/configure b/configure index 30c2315dc..290fdd283 100755 --- a/configure +++ b/configure @@ -1,5 +1,5 @@ #! /bin/sh -# From configure.ac for Bash 5.3, version 5.059. +# From configure.ac for Bash 5.3, version 5.060. # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.71 for bash 5.3-devel. # @@ -8454,21 +8454,19 @@ $ac_includes_default VM page cache was not coherent with the file system buffer cache like early versions of FreeBSD and possibly contemporary NetBSD.) For shared mappings, we should conversely verify that changes get - propagated back to all the places they're supposed to be. - - Grep wants private fixed already mapped. - The main things grep needs to know about mmap are: - * does it exist and is it safe to write into the mmap'd area - * how to use it (BSD variants) */ + propagated back to all the places they're supposed to be. */ #include #include -/* This mess was copied from the GNU getpagesize.h. */ -#ifndef HAVE_GETPAGESIZE +#ifndef getpagesize # ifdef _SC_PAGESIZE -# define getpagesize() sysconf(_SC_PAGESIZE) -# else /* no _SC_PAGESIZE */ +# define getpagesize() sysconf (_SC_PAGESIZE) +# elif defined _SC_PAGE_SIZE +# define getpagesize() sysconf (_SC_PAGE_SIZE) +# elif HAVE_GETPAGESIZE +int getpagesize (); +# else # ifdef HAVE_SYS_PARAM_H # include # ifdef EXEC_PAGESIZE @@ -8492,16 +8490,15 @@ $ac_includes_default # else /* no HAVE_SYS_PARAM_H */ # define getpagesize() 8192 /* punt totally */ # endif /* no HAVE_SYS_PARAM_H */ -# endif /* no _SC_PAGESIZE */ - -#endif /* no HAVE_GETPAGESIZE */ +# endif +#endif int main (void) { char *data, *data2, *data3; const char *cdata2; - int i, pagesize; + long i, pagesize; int fd, fd2; pagesize = getpagesize (); @@ -9058,8 +9055,8 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam \ LIBS=$save_LIBS test $gl_pthread_api = yes && break done - echo "$as_me:9061: gl_pthread_api=$gl_pthread_api" >&5 - echo "$as_me:9062: LIBPTHREAD=$LIBPTHREAD" >&5 + echo "$as_me:9058: gl_pthread_api=$gl_pthread_api" >&5 + echo "$as_me:9059: LIBPTHREAD=$LIBPTHREAD" >&5 gl_pthread_in_glibc=no # On Linux with glibc >= 2.34, libc contains the fully functional @@ -9085,7 +9082,7 @@ rm -rf conftest* ;; esac - echo "$as_me:9088: gl_pthread_in_glibc=$gl_pthread_in_glibc" >&5 + echo "$as_me:9085: gl_pthread_in_glibc=$gl_pthread_in_glibc" >&5 # Test for libpthread by looking for pthread_kill. (Not pthread_self, # since it is defined as a macro on OSF/1.) @@ -9239,7 +9236,7 @@ fi fi fi - echo "$as_me:9242: LIBPMULTITHREAD=$LIBPMULTITHREAD" >&5 + echo "$as_me:9239: LIBPMULTITHREAD=$LIBPMULTITHREAD" >&5 fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether POSIX threads API is available" >&5 printf %s "checking whether POSIX threads API is available... " >&6; } @@ -9467,8 +9464,8 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam \ LIBS=$save_LIBS test $gl_pthread_api = yes && break done - echo "$as_me:9470: gl_pthread_api=$gl_pthread_api" >&5 - echo "$as_me:9471: LIBPTHREAD=$LIBPTHREAD" >&5 + echo "$as_me:9467: gl_pthread_api=$gl_pthread_api" >&5 + echo "$as_me:9468: LIBPTHREAD=$LIBPTHREAD" >&5 gl_pthread_in_glibc=no # On Linux with glibc >= 2.34, libc contains the fully functional @@ -9494,7 +9491,7 @@ rm -rf conftest* ;; esac - echo "$as_me:9497: gl_pthread_in_glibc=$gl_pthread_in_glibc" >&5 + echo "$as_me:9494: gl_pthread_in_glibc=$gl_pthread_in_glibc" >&5 # Test for libpthread by looking for pthread_kill. (Not pthread_self, # since it is defined as a macro on OSF/1.) @@ -9648,7 +9645,7 @@ fi fi fi - echo "$as_me:9651: LIBPMULTITHREAD=$LIBPMULTITHREAD" >&5 + echo "$as_me:9648: LIBPMULTITHREAD=$LIBPMULTITHREAD" >&5 fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether POSIX threads API is available" >&5 printf %s "checking whether POSIX threads API is available... " >&6; } @@ -16302,21 +16299,19 @@ $ac_includes_default VM page cache was not coherent with the file system buffer cache like early versions of FreeBSD and possibly contemporary NetBSD.) For shared mappings, we should conversely verify that changes get - propagated back to all the places they're supposed to be. - - Grep wants private fixed already mapped. - The main things grep needs to know about mmap are: - * does it exist and is it safe to write into the mmap'd area - * how to use it (BSD variants) */ + propagated back to all the places they're supposed to be. */ #include #include -/* This mess was copied from the GNU getpagesize.h. */ -#ifndef HAVE_GETPAGESIZE +#ifndef getpagesize # ifdef _SC_PAGESIZE -# define getpagesize() sysconf(_SC_PAGESIZE) -# else /* no _SC_PAGESIZE */ +# define getpagesize() sysconf (_SC_PAGESIZE) +# elif defined _SC_PAGE_SIZE +# define getpagesize() sysconf (_SC_PAGE_SIZE) +# elif HAVE_GETPAGESIZE +int getpagesize (); +# else # ifdef HAVE_SYS_PARAM_H # include # ifdef EXEC_PAGESIZE @@ -16340,16 +16335,15 @@ $ac_includes_default # else /* no HAVE_SYS_PARAM_H */ # define getpagesize() 8192 /* punt totally */ # endif /* no HAVE_SYS_PARAM_H */ -# endif /* no _SC_PAGESIZE */ - -#endif /* no HAVE_GETPAGESIZE */ +# endif +#endif int main (void) { char *data, *data2, *data3; const char *cdata2; - int i, pagesize; + long i, pagesize; int fd, fd2; pagesize = getpagesize (); @@ -18473,96 +18467,6 @@ printf "%s\n" "#define DUP2_BROKEN 1" >>confdefs.h fi - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether pgrps need synchronization" >&5 -printf %s "checking whether pgrps need synchronization... " >&6; } -if test ${bash_cv_pgrp_pipe+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if test "$cross_compiling" = yes -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cannot check pgrp synchronization if cross compiling -- defaulting to no" >&5 -printf "%s\n" "$as_me: WARNING: cannot check pgrp synchronization if cross compiling -- defaulting to no" >&2;} - bash_cv_pgrp_pipe=no - -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#ifdef HAVE_UNISTD_H -# include -#endif -#ifdef HAVE_SYS_WAIT_H -# include -#endif -#include -int -main() -{ -# ifdef GETPGRP_VOID -# define getpgID() getpgrp() -# else -# define getpgID() getpgrp(0) -# define setpgid(x,y) setpgrp(x,y) -# endif - int pid1, pid2, fds[2]; - int status; - char ok; - - switch (pid1 = fork()) { - case -1: - exit(1); - case 0: - setpgid(0, getpid()); - exit(0); - } - setpgid(pid1, pid1); - - sleep(2); /* let first child die */ - - if (pipe(fds) < 0) - exit(2); - - switch (pid2 = fork()) { - case -1: - exit(3); - case 0: - setpgid(0, pid1); - ok = getpgID() == pid1; - write(fds[1], &ok, 1); - exit(0); - } - setpgid(pid2, pid1); - - close(fds[1]); - if (read(fds[0], &ok, 1) != 1) - exit(4); - wait(&status); - wait(&status); - exit(ok ? 0 : 5); -} - -_ACEOF -if ac_fn_c_try_run "$LINENO" -then : - bash_cv_pgrp_pipe=no -else $as_nop - bash_cv_pgrp_pipe=yes -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - -fi - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $bash_cv_pgrp_pipe" >&5 -printf "%s\n" "$bash_cv_pgrp_pipe" >&6; } -if test $bash_cv_pgrp_pipe = yes; then -printf "%s\n" "#define PGRP_PIPE 1" >>confdefs.h - -fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for type of signal functions" >&5 printf %s "checking for type of signal functions... " >&6; } if test ${bash_cv_signal_vintage+y} @@ -18701,6 +18605,9 @@ printf "%s\n" "#define HAVE_USG_SIGHOLD 1" >>confdefs.h fi +printf "%s\n" "#define PGRP_PIPE 1" >>confdefs.h + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sys_errlist and sys_nerr" >&5 printf %s "checking for sys_errlist and sys_nerr... " >&6; } if test ${bash_cv_sys_errlist+y} diff --git a/configure.ac b/configure.ac index c25a8088e..e616e2fff 100644 --- a/configure.ac +++ b/configure.ac @@ -5,7 +5,7 @@ dnl report bugs to chet@po.cwru.edu dnl dnl Process this file with autoconf to produce a configure script. -# Copyright (C) 1987-2023 Free Software Foundation, Inc. +# Copyright (C) 1987-2024 Free Software Foundation, Inc. # # This program is free software: you can redistribute it and/or modify @@ -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.3, version 5.059])dnl +AC_REVISION([for Bash 5.3, version 5.060])dnl define(bashvers, 5.3) define(relstatus, devel) @@ -1030,9 +1030,12 @@ fi dnl behavior of system calls and library functions BASH_FUNC_DUP2_CLOEXEC_CHECK -BASH_SYS_PGRP_SYNC BASH_SYS_SIGNAL_VINTAGE +dnl https://lists.gnu.org/archive/html/bug-bash/2024-01/msg00047.html +dnl BASH_SYS_PGRP_SYNC +AC_DEFINE(PGRP_PIPE) + dnl checking for the presence of certain library symbols BASH_SYS_ERRLIST BASH_SYS_SIGLIST diff --git a/externs.h b/externs.h index 832ab203d..6bd136641 100644 --- a/externs.h +++ b/externs.h @@ -212,6 +212,9 @@ extern void clock_t_to_secs (clock_t, time_t *, long *); extern void print_clock_t (FILE *, clock_t); #endif +/* Declarations for functions defined in lib/sh/compat.c */ +extern int compat_init (void); + /* Declarations for functions defined in lib/sh/dprintf.c */ #if !defined (HAVE_DPRINTF) extern void dprintf (int, const char *, ...) __attribute__((__format__ (printf, 2, 3))); diff --git a/jobs.c b/jobs.c index 59c464754..3e68bf24a 100644 --- a/jobs.c +++ b/jobs.c @@ -3247,7 +3247,8 @@ wait_for_any_job (int flags, struct procstat *ps) int i, r; sigset_t set, oset; - if (jobs_list_frozen) + /* Allow funsubs to run this, but don't remove jobs from the jobs table. */ + if (jobs_list_frozen && executing_funsub == 0) return -1; /* First see if there are any unnotified dead jobs that we can report on */ @@ -3266,8 +3267,11 @@ return_job: ps->pid = pid; ps->status = r; } - notify_of_job_status (); /* XXX */ - delete_job (i, 0); + if (jobs_list_frozen == 0) /* must be running a funsub to get here */ + { + notify_of_job_status (); /* XXX */ + delete_job (i, 0); + } #if defined (COPROCESS_SUPPORT) coproc_reap (); #endif diff --git a/lib/sh/eaccess.c b/lib/sh/eaccess.c index 0859b6b34..abeead2d6 100644 --- a/lib/sh/eaccess.c +++ b/lib/sh/eaccess.c @@ -109,7 +109,7 @@ sh_stat (const char *path, struct stat *finfo) effectively a no-op. */ pbuf = xrealloc (pbuf, sizeof (DEV_FD_PREFIX) + strlen (path + 8)); strcpy (pbuf, DEV_FD_PREFIX); - strcat (pbuf, path + 8); + strcpy (pbuf + sizeof (DEV_FD_PREFIX) - 1, path + 8); return (stat (pbuf, finfo)); #endif /* !HAVE_DEV_FD */ } diff --git a/lib/sh/tmpfile.c b/lib/sh/tmpfile.c index 83e368496..650c0ac0e 100644 --- a/lib/sh/tmpfile.c +++ b/lib/sh/tmpfile.c @@ -169,7 +169,7 @@ sh_mktmpname (const char *nameroot, int flags) if (flags & MT_TEMPLATE) strcpy (filename, nameroot); else - sprintf (filename, "%s/%s.XXXXXX", tdir, lroot); + snprintf (filename, PATH_MAX, "%s/%s.XXXXXX", tdir, lroot); if (mktemp (filename) == 0) { free (filename); @@ -191,7 +191,7 @@ sh_mktmpname (const char *nameroot, int flags) (unsigned long) time ((time_t *)0) ^ (unsigned long) dollar_dollar_pid ^ x; - sprintf (filename, "%s/%s-%lu", tdir, lroot, filenum); + snprintf (filename, PATH_MAX, "%s/%s-%lu", tdir, lroot, filenum); if (tmpnamelen > 0 && tmpnamelen < 32) /* XXX */ filename[tdlen + 1 + tmpnamelen] = '\0'; # ifdef HAVE_LSTAT @@ -229,7 +229,7 @@ sh_mktmpfd (const char *nameroot, int flags, char **namep) if (flags & MT_TEMPLATE) strcpy (filename, nameroot); else - sprintf (filename, "%s/%s.XXXXXX", tdir, lroot); + snprintf (filename, PATH_MAX, "%s/%s.XXXXXX", tdir, lroot); fd = mkstemp (filename); if ((flags & MT_UNLINK) && tmpunlink (filename) < 0) { @@ -263,7 +263,7 @@ sh_mktmpfd (const char *nameroot, int flags, char **namep) (unsigned long) time ((time_t *)0) ^ (unsigned long) dollar_dollar_pid ^ x; - sprintf (filename, "%s/%s-%lu", tdir, lroot, filenum); + snprintf (filename, PATH_MAX, "%s/%s-%lu", tdir, lroot, filenum); if (tmpnamelen > 0 && tmpnamelen < 32) /* XXX */ filename[tdlen + 1 + tmpnamelen] = '\0'; fd = open (filename, BASEOPENFLAGS | ((flags & MT_READWRITE) ? O_RDWR : O_WRONLY), 0600); @@ -329,7 +329,7 @@ sh_mktmpdir (const char *nameroot, int flags) if (flags & MT_TEMPLATE) strcpy (filename, nameroot); else - sprintf (filename, "%s/%s.XXXXXX", tdir, lroot); + snprintf (filename, PATH_MAX, "%s/%s.XXXXXX", tdir, lroot); dirname = mkdtemp (filename); if (dirname == 0) { diff --git a/parse.y b/parse.y index dbc3fe6d8..884daff07 100644 --- a/parse.y +++ b/parse.y @@ -6995,21 +6995,11 @@ parse_compound_assignment (size_t *retlenp) wl = make_word_list (yylval.word, wl); } - /* Check whether or not an alias got popped out from underneath us and - fix up after restore_parser_state. */ - if (ea && ss && ss != pushed_string_list) - { - restore_pushed_strings = 1; - ss = pushed_string_list; - } - restore_parser_state (&ps); - if (restore_pushed_strings) - pushed_string_list = ss; - if (wl == &parse_string_error) { set_exit_status (EXECUTION_FAILURE); last_read_token = current_token = '\n'; /* XXX */ + /* This will eventually call reset_parser */ if (interactive_shell == 0 && posixly_correct) jump_to_top_level (FORCE_EOF); else @@ -7020,6 +7010,20 @@ parse_compound_assignment (size_t *retlenp) } } + /* Check whether or not an alias got popped out from underneath us and + fix up after restore_parser_state. */ + if (ea && ss && ss != pushed_string_list) + { + restore_pushed_strings = 1; + ss = pushed_string_list; + /* Don't bother with restoring the pushed string list from ps if we're + just going to overwrite it. */ + ps.pushed_strings = NULL; + } + restore_parser_state (&ps); + if (restore_pushed_strings) + pushed_string_list = ss; + if (wl) { rl = REVERSE_LIST (wl, WORD_LIST *); diff --git a/shell.c b/shell.c index 9a9798902..82c450fea 100644 --- a/shell.c +++ b/shell.c @@ -624,6 +624,8 @@ main (int argc, char **argv, char **env) gnu_error_format = 1; } + compat_init (); + top_level_arg_index = arg_index; old_errexit_flag = exit_immediately_on_error; diff --git a/subst.c b/subst.c index 585e49781..87b196233 100644 --- a/subst.c +++ b/subst.c @@ -6801,7 +6801,7 @@ uw_anonclose (void *fdesc) static void uw_unbind_variable (void *name) { - unbind_variable (name); + unbind_variable_noref (name); } static void diff --git a/tests/parser.right b/tests/parser.right index 3a01004fe..e0cdfac7a 100644 --- a/tests/parser.right +++ b/tests/parser.right @@ -1,3 +1,4 @@ +bash: -c: line 1: unexpected EOF while looking for matching `)' AAA bash5: line 1: `invalid-name': not a valid identifier in diff --git a/tests/parser.tests b/tests/parser.tests index c8750b973..51f566855 100644 --- a/tests/parser.tests +++ b/tests/parser.tests @@ -7,6 +7,9 @@ case x in x) if ((1)); then :; fi esac case x in x) if ((true ) ); then :; fi ;; esac case x in x) if ((true ) ); then :; fi esac +# problem with bash-5.2 +${THIS_SH} -c '((X=([))]' bash + # this has to be in a separate file to get desired EOF behavior ${THIS_SH} ./parser1.sub