From 6a9e77e881a90f7effc53c113299f6d856aeee6d Mon Sep 17 00:00:00 2001 From: Chet Ramey Date: Mon, 3 Jul 2023 10:26:23 -0400 Subject: [PATCH] fix up semantics of assigning to noassign variables; fix error message in arithmetic noeval mode; add shared memory option to anonymous files; fix static linking config in configure --- CWRU/CWRU.chlog | 31 +++++++++++++++++ arrayfunc.c | 38 ++++++++++++++------- builtins/declare.def | 8 +++-- config.h.in | 3 ++ configure | 11 ++++-- configure.ac | 8 +++-- doc/bashref.texi | 5 +-- doc/version.texi | 4 +-- expr.c | 26 ++++++++------ lib/sh/anonfile.c | 81 ++++++++++++++++++++++++++++++++++++++++---- tests/array.right | 6 ++++ tests/array.tests | 8 +++++ variables.c | 4 ++- 13 files changed, 189 insertions(+), 44 deletions(-) diff --git a/CWRU/CWRU.chlog b/CWRU/CWRU.chlog index 5529c78e..b149c619 100644 --- a/CWRU/CWRU.chlog +++ b/CWRU/CWRU.chlog @@ -6952,6 +6952,7 @@ arrayfunc.c - assign_compound_array_list: check for integer overflow if the max index of the array is already INT_MAX. From a report from Emanuele Torre + - assign_array_var_from_word_list: ditto 6/28 ---- @@ -6973,3 +6974,33 @@ bashline.c doc/bash.1,doc/bashref.texi - BASH_ARGC,BASH_ARGV,BASH_SOURCE,BASH_LINENO: note that these variables may not be assigned to or unset + + 6/29 + ---- +builtins/declare.def + - declare_internal: attempting to assign to a noassign variable is no + longer an assignment error; the attempt is just ignored + +arrayfunc.c + - find_or_make_array_variable: take a new flag value, 4: means to + return noassign variables as themselves instead of NULL without + performing the assignment so the caller can handle them differently. + - assign_array_from_string: pass flags & 4 to find_or_make_array_variable + so we can simply ignore attempted assignments to noassign array + variables instead of treating them as assignment errors + From a report by Kerin Millar + +expr.c + - exppower: only report negative exponent error if noeval == 0. + Fixes issue reported by Steffen Nurpmeso + + 6/30 + ---- +lib/sh/anonfile.c + - anonopen: add support for using shm_open or shm_mkstemp to create + an anonymous file using POSIX shared memory + +configure.ac + - if --enable-static-link is supplied, add -static to LDFLAGS on + Linux if opt_profiling isn't enabled + From a report from Emanuele Torre diff --git a/arrayfunc.c b/arrayfunc.c index a92063bc..98e60d31 100644 --- a/arrayfunc.c +++ b/arrayfunc.c @@ -445,7 +445,8 @@ assign_array_element_internal (SHELL_VAR *entry, const char *name, char *vname, convert it to an indexed array. If FLAGS&1 is non-zero, an existing variable is checked for the readonly or noassign attribute in preparation for assignment (e.g., by the `read' builtin). If FLAGS&2 is non-zero, we - create an associative array. */ + create an associative array. If FLAGS&4 is non-zero, we return noassign + variables instead of NULL because the caller wants to handle them. */ SHELL_VAR * find_or_make_array_variable (const char *name, int flags) { @@ -479,6 +480,8 @@ find_or_make_array_variable (const char *name, int flags) { if (readonly_p (var)) err_readonly (name); + if ((flags & 4) && noassign_p (var)) + return (var); return ((SHELL_VAR *)NULL); } else if ((flags & 2) && array_p (var)) @@ -506,10 +509,11 @@ assign_array_from_string (const char *name, char *value, int flags) vflags = 1; if (flags & ASS_MKASSOC) vflags |= 2; + vflags |= 4; /* we want to handle noassign variables ourselves */ var = find_or_make_array_variable (name, vflags); - if (var == 0) - return ((SHELL_VAR *)NULL); + if (var == 0 || noassign_p (var)) + return (var); return (assign_array_var_from_string (var, value, flags)); } @@ -525,6 +529,15 @@ assign_array_var_from_word_list (SHELL_VAR *var, WORD_LIST *list, int flags) a = array_cell (var); i = (flags & ASS_APPEND) ? array_max_index (a) + 1 : 0; + if (a && i < 0) /* overflow */ + { + char *num; + + num = itos (i); + report_error ("%s[%s]: %s", var->name, num, bash_badsub_errmsg); + free (num); + return (var); /* XXX */ + } for (l = list; l; l = l->next, i++) bind_array_var_internal (var, i, 0, l->word->word, flags & ~ASS_APPEND); @@ -705,15 +718,6 @@ assign_compound_array_list (SHELL_VAR *var, WORD_LIST *nlist, int flags) } last_ind = (a && (flags & ASS_APPEND)) ? array_max_index (a) + 1 : 0; - if (a && last_ind < 0) /* overflow */ - { - char *num; - - num = itos (last_ind); - report_error ("%s[%s]: %s", var->name, num, bash_badsub_errmsg); - free (num); - return; - } #if ASSOC_KVPAIR_ASSIGNMENT if (assoc_p (var) && kvpair_assignment_p (nlist)) @@ -737,6 +741,16 @@ assign_compound_array_list (SHELL_VAR *var, WORD_LIST *nlist, int flags) iflags = flags & ~ASS_APPEND; w = list->word->word; + if (array_p (var) && last_ind < 0) /* overflow */ + { + char *num; + + num = itos (last_ind); + report_error ("%s[%s]: %s", var->name, num, bash_badsub_errmsg); + free (num); + return; + } + /* We have a word of the form [ind]=value */ if ((list->word->flags & W_ASSIGNMENT) && w[0] == '[') { diff --git a/builtins/declare.def b/builtins/declare.def index 337e6755..d3784855 100644 --- a/builtins/declare.def +++ b/builtins/declare.def @@ -844,8 +844,12 @@ restart_new_var_name: else if ((readonly_p (var) || noassign_p (var)) && offset) { if (readonly_p (var)) - sh_readonly (name); - assign_error++; + { + sh_readonly (name); + assign_error++; + } + /* just ignore attempts to assign to noassign variables; returning + EXECUTION_FAILURE would cause set -e to exit the shell. */ NEXT_VARIABLE (); } diff --git a/config.h.in b/config.h.in index c2750a2a..16103a8e 100644 --- a/config.h.in +++ b/config.h.in @@ -1226,6 +1226,9 @@ /* Define if you have the `munmap' function. */ #undef HAVE_MUNMAP +/* Define if you have the `nanosleep' function. */ +#undef HAVE_NANOSLEEP + /* Define if you have the `nl_langinfo' function. */ #undef HAVE_NL_LANGINFO diff --git a/configure b/configure index 518b6fc2..9176f183 100755 --- a/configure +++ b/configure @@ -1,5 +1,5 @@ #! /bin/sh -# From configure.ac for Bash 5.3, version 5.054. +# From configure.ac for Bash 5.3, version 5.055. # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.71 for bash 5.3-devel. # @@ -5335,7 +5335,8 @@ if test "$opt_static_link" = yes; then if test "$GCC" = "yes"; then STATIC_LD="-static" case "$host_os" in - solaris2*|linux*) ;; + solaris2*) ;; + linux*) test "$opt_profiling" = "no" && LDFLAGS="$LDFLAGS -static" ;; *) LDFLAGS="$LDFLAGS -static" ;; # XXX experimental esac fi @@ -14959,6 +14960,12 @@ if test "x$ac_cv_func_lstat" = xyes then : printf "%s\n" "#define HAVE_LSTAT 1" >>confdefs.h +fi +ac_fn_c_check_func "$LINENO" "nanosleep" "ac_cv_func_nanosleep" +if test "x$ac_cv_func_nanosleep" = xyes +then : + printf "%s\n" "#define HAVE_NANOSLEEP 1" >>confdefs.h + fi ac_fn_c_check_func "$LINENO" "pselect" "ac_cv_func_pselect" if test "x$ac_cv_func_pselect" = xyes diff --git a/configure.ac b/configure.ac index 29f50438..477b6ffa 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.3, version 5.054])dnl +AC_REVISION([for Bash 5.3, version 5.055])dnl define(bashvers, 5.3) define(relstatus, devel) @@ -515,7 +515,8 @@ if test "$opt_static_link" = yes; then if test "$GCC" = "yes"; then STATIC_LD="-static" case "$host_os" in - solaris2*|linux*) ;; + solaris2*) ;; + linux*) test "$opt_profiling" = "no" && LDFLAGS="$LDFLAGS -static" ;; *) LDFLAGS="$LDFLAGS -static" ;; # XXX experimental esac fi @@ -843,7 +844,8 @@ AC_CHECK_FUNC(mkfifo, AC_DEFINE(HAVE_MKFIFO), AC_DEFINE(MKFIFO_MISSING)) dnl checks for system calls AC_CHECK_FUNCS(dup2 eaccess fcntl getdtablesize getentropy getgroups \ gethostname getpagesize getpeername getrandom getrlimit \ - getrusage gettimeofday kill killpg lstat pselect readlink \ + getrusage gettimeofday kill killpg lstat nanosleep \ + pselect readlink \ select setdtablesize setitimer tcgetpgrp uname ulimit waitpid) AC_REPLACE_FUNCS(rename) diff --git a/doc/bashref.texi b/doc/bashref.texi index b8cf474e..37a0f5b8 100644 --- a/doc/bashref.texi +++ b/doc/bashref.texi @@ -1953,7 +1953,7 @@ command substitution. After these expansions are performed, quote characters present in the original word are removed unless they have been quoted themselves -(@dfn{quote removal}). +(@dfn{quote removal}). @xref{Quote Removal} for more details. Only brace expansion, word splitting, and filename expansion can increase the number of words of the expansion; other expansions @@ -1963,9 +1963,6 @@ The only exceptions to this are the expansions of @code{"$@{@var{name}[@@]@}"} and @code{$@{@var{name}[*]@}} (@pxref{Arrays}). -After all expansions, @code{quote removal} (@pxref{Quote Removal}) -is performed. - @node Brace Expansion @subsection Brace Expansion @cindex brace expansion diff --git a/doc/version.texi b/doc/version.texi index b9bc389b..159f956f 100644 --- a/doc/version.texi +++ b/doc/version.texi @@ -2,10 +2,10 @@ Copyright (C) 1988-2023 Free Software Foundation, Inc. @end ignore -@set LASTCHANGE Wed Jun 28 14:06:44 EDT 2023 +@set LASTCHANGE Thu Jun 29 16:25:08 EDT 2023 @set EDITION 5.3 @set VERSION 5.3 -@set UPDATED 28 June 2023 +@set UPDATED 29 June 2023 @set UPDATED-MONTH June 2023 diff --git a/expr.c b/expr.c index 45fb2f36..9f711a9b 100644 --- a/expr.c +++ b/expr.c @@ -960,11 +960,16 @@ exppower (void) readtok (); val2 = exppower (); /* exponentiation is right-associative */ lasttok = NUM; - if (val2 == 0) - return (1); - if (val2 < 0) - evalerror (_("exponent less than 0")); - val1 = ipow (val1, val2); + if (noeval == 0) + { + if (val2 == 0) + return (1); + if (val2 < 0) + evalerror (_("exponent less than 0")); + val1 = ipow (val1, val2); + } + else + val1 = 1; } return (val1); } @@ -1342,7 +1347,7 @@ readtok (void) e = ']'; } else - evalerror (bash_badsub_errmsg); + evalerror (_(bash_badsub_errmsg)); } #endif /* ARRAY_VARS */ @@ -1442,11 +1447,10 @@ readtok (void) #endif { /* This catches something like --FOO++ */ - /* TAG:bash-5.3 add gettext calls here or make this a separate function */ if (c == '-') - evalerror ("--: assignment requires lvalue"); + evalerror (_("--: assignment requires lvalue")); else - evalerror ("++: assignment requires lvalue"); + evalerror (_("++: assignment requires lvalue")); } else if ((c == '-' || c == '+') && c1 == c) { @@ -1465,9 +1469,9 @@ readtok (void) preinc and predec. */ /* This catches something like --4++ */ if (c == '-') - evalerror ("--: assignment requires lvalue"); + evalerror (_("--: assignment requires lvalue")); else - evalerror ("++: assignment requires lvalue"); + evalerror (_("++: assignment requires lvalue")); } #else cp--; /* not preinc or predec, so unget the character */ diff --git a/lib/sh/anonfile.c b/lib/sh/anonfile.c index 9a805b2d..b3c8957c 100644 --- a/lib/sh/anonfile.c +++ b/lib/sh/anonfile.c @@ -35,21 +35,72 @@ #include #include -/* Placeholder for future use of memfd_create/shm_open/shm_mkstemp */ +static int anonunlink (const char *); + +#if defined (HAVE_SHM_OPEN) +#ifndef O_NOFOLLOW +# define O_NOFOLLOW 0 +#endif static int -anonunlink (const char *fn) +anonshmunlink (const char *fn) { - int r; - - r = unlink (fn); - return r; + return (shm_unlink (fn)); } +static int +anonshmopen (const char *name, int flags, char **fn) +{ + int fd; + char *fname; + + fd = -1; + if (fn) + *fn = 0; + +#if defined (HAVE_SHM_MKSTEMP) + fname = savestring ("/shm-XXXXXXXXXX"); + fd = shm_mkstemp (fname); + if (fd < 0) + free (fname); +#endif + + if (fd < 0) + { + fname = sh_mktmpname (name, flags); + fd = shm_open (fname, O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW, 0600); + } + + if (fd < 0) + { + free (fname); + return fd; + } + + if (shm_unlink (fname) < 0) + { + int o; + o = errno; + free (fname); + close (fd); + errno = o; + return -1; + } + + if (fn) + *fn = fname; + else + free (fname); + + return fd; +} +#endif + int anonopen (const char *name, int flags, char **fn) { int fd, flag; + char *fname; #if defined (HAVE_MEMFD_CREATE) /* "Names do not affect the behavior of the file descriptor." */ @@ -60,12 +111,19 @@ anonopen (const char *name, int flags, char **fn) *fn = 0; return fd; } - /* If memfd_create fails, we fall through to the unlinked-regular-file + /* If memfd_create fails, we fall through to the unlinked-shm-or-regular-file implementation. */ #endif /* Heuristic */ flag = (name && *name == '/') ? MT_TEMPLATE : MT_USETMPDIR; + +#if defined (HAVE_SHM_OPEN) + fd = anonshmopen (name, flag, fn); + if (fd >= 0) + return fd; /* anonshmopen sets *FN appropriately */ +#endif + fd = sh_mktmpfd (name, flag|MT_USERANDOM|MT_READWRITE|MT_UNLINK, fn); return fd; } @@ -78,3 +136,12 @@ anonclose (int fd, const char *name) r = close (fd); return r; } + +static int +anonunlink (const char *fn) +{ + int r; + + r = unlink (fn); + return r; +} diff --git a/tests/array.right b/tests/array.right index eebf1068..aebe24d2 100644 --- a/tests/array.right +++ b/tests/array.right @@ -206,6 +206,12 @@ e b c $0 declare -a A=([0]="X=a" [1]="b") +FIN1:0 +FIN2:0 +FIN3:0 +FIN4:0 +FIN5:0 +FIN6:0 t [3]=abcde r s t u v e diff --git a/tests/array.tests b/tests/array.tests index 126ced3b..7e5a6376 100644 --- a/tests/array.tests +++ b/tests/array.tests @@ -397,6 +397,14 @@ Z='a b' A=( X=$Z ) declare -p A +# tests for assigning to noassign array variables +BASH_ARGC=(xxx) ; echo FIN1:$? +BASH_ARGC=foio ; echo FIN2:$? +declare BASH_ARGC=(xxx) ; echo FIN3:$? +declare BASH_ARGC=foio ; echo FIN4:$? +BASH_ARGV[1]=foo ; echo FIN5:$? +declare BASH_ARGV[1]=foo ; echo FIN6:$? + # tests for bash-3.1 problems ${THIS_SH} ./array5.sub diff --git a/variables.c b/variables.c index 2db4a457..05a0daa0 100644 --- a/variables.c +++ b/variables.c @@ -464,7 +464,7 @@ initialize_shell_variables (char **env, int privmode) temp_string = extract_array_assignment_list (string, &string_length); temp_var = assign_array_from_string (tname, temp_string, 0); FREE (temp_string); - if (temp_var) + if (temp_var && noassign_p (temp_var) == 0) { VSETATTR (temp_var, (att_exported | att_imported)); array_needs_making = 1; @@ -484,6 +484,8 @@ initialize_shell_variables (char **env, int privmode) /* need to make sure it exists as an associative array first */ temp_var = find_or_make_array_variable (tname, 2); + if (temp_var && noassign_p (temp_var)) + temp_var = 0; if (temp_var) { string_length = 1;