]> git.ipfire.org Git - thirdparty/bash.git/commitdiff
fix issue with interupting timed functions; fix for parsing comsubs inside arith...
authorChet Ramey <chet.ramey@case.edu>
Mon, 3 Jun 2024 13:09:11 +0000 (09:09 -0400)
committerChet Ramey <chet.ramey@case.edu>
Mon, 3 Jun 2024 13:09:11 +0000 (09:09 -0400)
20 files changed:
CWRU/CWRU.chlog
arrayfunc.c
builtins/declare.def
builtins/getopts.def
builtins/printf.def
builtins/read.def
config.h.in
configure
configure.ac
execute_cmd.c
expr.c
lib/readline/complete.c
lib/readline/text.c
lib/sh/zread.c
quit.h
redir.c
subst.c
tests/arith-for.tests
variables.c
variables.h

index a6416f31e10c7cc1f6d5a64e401021e9de4662bb..b902d7c34591e385c802a0fb37be6f85b9efda00 100644 (file)
@@ -9521,3 +9521,72 @@ execute_cmd.c
        - shell_execve: fix typo in code that chops \r off the end of the #!
          interpreter
          Report and fix from Collin Funk <collin.funk1@gmail.com>
+
+                                  5/28
+                                  ----
+execute_cmd.c
+       - time_command: only restore command->flags if we haven't longjmped
+         Report from Michael Maurer <michael.maurer@univie.ac.at> and
+         Grisha Levit <grishalevit@gmail.com>
+
+subst.c
+       - skip_to_delim: if we're not skipping over command substitutions
+         lexically, call extract_command_subst instead of using the old
+         extract_delimited_string
+         Fixes bug reported by Oguz <oguzismailuysal@gmail.com>
+
+execute_cmd.c
+       - execute_arith_for_command: handle the extremely unlikely case that
+         the step or test expressions execute `break' or `continue' in a
+         nofork command substitution
+         Report from Oguz <oguzismailuysal@gmail.com>
+
+                                  5/29
+                                  ----
+lib/readline/complete.c
+       - compute_lcd_of_matches: if we have multiple matches that compare
+         equally when using case-insensitive completion, but are different
+         lengths due to the presence of multibyte characters, use the
+         shorter match as the common prefix to avoid overflow
+         Report from Grisha Levit <grishalevit@gmail.com>
+
+                                  5/30
+                                  ----
+lib/readline/text.c
+       - _rl_readstr_init: don't call rl_maybe_replace_line since we're not
+         actually moving off this history line
+         Report from Grisha Levit <grishalevit@gmail.com>
+
+builtins/read.def
+       - read_builtin: free ifs_chars in more return code paths
+         Report and patch from Grisha Levit <grishalevit@gmail.com>
+
+                                  5/31
+                                  ----
+quit.h
+       - ZRESET: new macro, calls zreset() if interrupt_state is non-zero
+
+lib/sh/zread.c
+       - zread: if read returns -1/EINTR, and we're executing a builtin,
+         call zreset just in case
+
+builtins/read.def
+       - read_builtin: if read returns > 0 (partial read) but interrupt_state
+         is non-zero, we're going to call throw_to_top_level, so call
+         ZRESET before that happens
+         Report from Oguz <oguzismailuysal@gmail.com>
+       - read_builtin: if zread/zreadc/zreadintr/zreadcintr return -1/EINTR,
+         make sure we call ZRESET in case zread did not
+
+variables.h
+       - ASSIGN_DISALLOWED: macro that encapsulates when an assignment to
+         SHELL_VAR *v with flags f will be disallowed and fail
+
+arrayfunc.c,execute_cmd.c,expr.c,redir.c,subst.c,variables.c
+builtins/delare.def,builtins/getopts.def,builtins/printf.def,builtins/read.def
+       - use ASSIGN_DISALLOWED where appropriate
+
+arrayfunc.c
+       - assign_array_element_internal: if the assignment failed, as tested by
+         ASSIGN_DISALLOWED, free the assoc array key we allocated
+         Report from Grisha Levit <grishalevit@gmail.com>
index e85ba6e5389ffcdd5db6308565ab497ea839f407..72921a18ef4197ee1b9d8e9c0f6ca4b609d7cfed 100644 (file)
@@ -276,7 +276,7 @@ bind_array_variable (const char *name, arrayind_t ind, const char *value, int fl
     }
   if (entry == (SHELL_VAR *) 0)
     entry = make_new_array_variable (name);
-  else if ((readonly_p (entry) && (flags&ASS_FORCE) == 0) || noassign_p (entry))
+  else if (ASSIGN_DISALLOWED (entry, flags))
     {
       if (readonly_p (entry))
        err_readonly (name);
@@ -298,7 +298,7 @@ bind_array_element (SHELL_VAR *entry, arrayind_t ind, char *value, int flags)
 SHELL_VAR *
 bind_assoc_variable (SHELL_VAR *entry, const char *name, char *key, const char *value, int flags)
 {
-  if ((readonly_p (entry) && (flags&ASS_FORCE) == 0) || noassign_p (entry))
+  if (ASSIGN_DISALLOWED (entry, flags))
     {
       if (readonly_p (entry))
        err_readonly (name);
@@ -406,6 +406,9 @@ assign_array_element_internal (SHELL_VAR *entry, const char *name, char *vname,
       if (estatep)
        nkey = savestring (akey);       /* assoc_insert/assoc_replace frees akey */
       entry = bind_assoc_variable (entry, vname, akey, value, flags);
+      /* If we didn't perform the assignment, free the key we allocated */
+      if (entry == 0 || (ASSIGN_DISALLOWED (entry, flags)))
+       FREE (akey);
       if (estatep)
        {
          estatep->type = ARRAY_ASSOC;
@@ -476,7 +479,7 @@ find_or_make_array_variable (const char *name, int flags)
 
   if (var == 0)
     var = (flags & 2) ? make_new_assoc_variable (name) : make_new_array_variable (name);
-  else if ((flags & 1) && (readonly_p (var) || noassign_p (var)))
+  else if ((flags & 1) && ASSIGN_DISALLOWED(var, 0))
     {
       if (readonly_p (var))
        err_readonly (name);
index 62bb0494615bad97e69c8c860bc22db58704160b..8065f8d28c959781b2c7e61b15f2254ac67bce93 100644 (file)
@@ -879,7 +879,7 @@ restart_new_var_name:
          NEXT_VARIABLE ();
        }
       /* Cannot use declare to assign value to readonly or noassign variable. */
-      else if ((readonly_p (var) || noassign_p (var)) && offset)
+      else if (ASSIGN_DISALLOWED (var, 0) && offset)
        {
          if (readonly_p (var))
            {
index 7f30bbb6195532188b8531ecacc0649681f97c9d..24e3a3b278144e0c1ede11b98694cd70f49cb425 100644 (file)
@@ -117,7 +117,7 @@ getopts_bind_variable (char *name, char *value)
   if (valid_identifier (name))
     {
       v = bind_variable (name, value, 0);
-      if (v && (readonly_p (v) || noassign_p (v)))
+      if (v && ASSIGN_DISALLOWED (v, 0))
        return (EX_MISCERROR);
       return (v ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
     }
index 2a98503149e318860fc8f7d369cb833b6ef29f5d..4d663225a3c47d16af55f7255fbbb6841219b4a1 100644 (file)
@@ -111,7 +111,7 @@ extern int errno;
          SHELL_VAR *v; \
          v = builtin_bind_variable  (vname, vbuf, bindflags); \
          stupidly_hack_special_variables (vname); \
-         if (v == 0 || readonly_p (v) || noassign_p (v)) \
+         if (v == 0 || ASSIGN_DISALLOWED (v, 0)) \
            retval = EXECUTION_FAILURE; \
          if (vbsize > 4096) \
            { \
@@ -334,7 +334,7 @@ printf_builtin (WORD_LIST *list)
       SHELL_VAR *v;
       v = builtin_bind_variable (vname, "", 0);
       stupidly_hack_special_variables (vname);
-      return ((v == 0 || readonly_p (v) || noassign_p (v)) ? EXECUTION_FAILURE : EXECUTION_SUCCESS);
+      return ((v == 0 || ASSIGN_DISALLOWED (v, 0)) ? EXECUTION_FAILURE : EXECUTION_SUCCESS);
     }
 
   /* If the format string is empty after preprocessing, return immediately. */
index 37328efc8848577c113ac144e1a1a02f47ae12ff..bccfdcf1f7dd3ac91a7871f0975e2f8205f6783b 100644 (file)
@@ -635,6 +635,8 @@ read_builtin (WORD_LIST *list)
          if (fd2 >= 0)
            close (fd2);
          run_unwind_frame ("read_builtin");
+         if (free_ifs)
+           free (ifs_chars);
          return (EXECUTION_FAILURE);
        }
 
@@ -746,6 +748,7 @@ read_builtin (WORD_LIST *list)
          x = errno;
          if (retval < 0 && errno == EINTR)
            {
+             ZRESET ();
              check_signals ();         /* in case we didn't call zread via zreadc */
              lastsig = LASTSIG();
              if (lastsig == 0)
@@ -764,6 +767,10 @@ read_builtin (WORD_LIST *list)
          break;
        }
 
+      /* Even if read returns a partial buffer, if we got an interrupt we're
+        going to throw it away. */
+      ZRESET();
+
       QUIT;            /* in case we didn't call check_signals() */
 #if defined (READLINE)
        }
@@ -894,6 +901,8 @@ add_char:
       if (errno != EINTR)
        builtin_error ("%d: %s: %s", fd, _("read error"), strerror (errno));
       run_unwind_frame ("read_builtin");
+      if (free_ifs)
+       free (ifs_chars);
       return ((t_errno != EINTR) ? EXECUTION_FAILURE : 128+lastsig);
     }
 
@@ -943,6 +952,8 @@ assign_vars:
       if (var == 0)
        {
          free (input_string);
+         if (free_ifs)
+           free (ifs_chars);
          return EXECUTION_FAILURE;     /* readonly or noassign */
        }
 
@@ -957,6 +968,8 @@ assign_vars:
          dispose_words (alist);
        }
       free (input_string);
+      if (free_ifs)
+       free (ifs_chars);
       return (retval);
     }
 #endif /* ARRAY_VARS */ 
@@ -987,12 +1000,14 @@ assign_vars:
        }
       else
        var = bind_variable ("REPLY", input_string, 0);
-      if (var == 0 || readonly_p (var) || noassign_p (var))
+      if (var == 0 || ASSIGN_DISALLOWED (var, 0))
        retval = EX_MISCERROR;
       else
        VUNSETATTR (var, att_invisible);
 
       free (input_string);
+      if (free_ifs)
+       free (ifs_chars);
       return (retval);
     }
 
@@ -1017,6 +1032,8 @@ assign_vars:
        {
          sh_invalidid (varname);
          free (orig_input_string);
+         if (free_ifs)
+           free (ifs_chars);
          return (EXECUTION_FAILURE);
        }
 
@@ -1049,6 +1066,8 @@ assign_vars:
       if (var == 0)
        {
          free (orig_input_string);
+         if (free_ifs)
+           free (ifs_chars);
          return (EX_MISCERROR);
        }
 
@@ -1066,6 +1085,8 @@ assign_vars:
     {
       sh_invalidid (list->word->word);
       free (orig_input_string);
+      if (free_ifs)
+       free (ifs_chars);
       return (EXECUTION_FAILURE);
     }
 
@@ -1123,8 +1144,7 @@ bind_read_variable (char *name, char *value, int flags)
   SHELL_VAR *v;
 
   v = builtin_bind_variable (name, value, flags);
-  return (v == 0 ? v
-                : ((readonly_p (v) || noassign_p (v)) ? (SHELL_VAR *)NULL : v));
+  return ((v == 0 || ASSIGN_DISALLOWED (v, 0)) ? (SHELL_VAR *)NULL : v);
 }
 
 #if defined (HANDLE_MULTIBYTE)
index cee53587d95b7c8e4412fb3fc99ac70ad13c4cd9..84113a8fd115bd6cd1296dfb19bf1ec661fc8059 100644 (file)
 /* Define if you have the tcgetpgrp function.  */
 #undef HAVE_TCGETPGRP
 
+/* Define if you have the tcgetwinsize function.  */
+#undef HAVE_TCGETWINSIZE
+
+/* Define if you have the tcsetwinsize function.  */
+#undef HAVE_SETWINSIZE
+
 /* Define if you have the times function.  */
 #undef HAVE_TIMES
 
index 49d85cf3ae428a4eacce9e982ec89a89b4e68741..6977651a01b2a6c3a57774e865cf58e1dad050da 100755 (executable)
--- a/configure
+++ b/configure
@@ -1,5 +1,5 @@
 #! /bin/sh
-# From configure.ac for Bash 5.3, version 5.064.
+# From configure.ac for Bash 5.3, version 5.065.
 # Guess values for system-dependent variables and create Makefiles.
 # Generated by GNU Autoconf 2.72 for bash 5.3-alpha.
 #
@@ -15757,6 +15757,18 @@ if test "x$ac_cv_func_tcgetattr" = xyes
 then :
   printf "%s\n" "#define HAVE_TCGETATTR 1" >>confdefs.h
 
+fi
+ac_fn_c_check_func "$LINENO" "tcgetwinsize" "ac_cv_func_tcgetwinsize"
+if test "x$ac_cv_func_tcgetwinsize" = xyes
+then :
+  printf "%s\n" "#define HAVE_TCGETWINSIZE 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "tcsetwinsize" "ac_cv_func_tcsetwinsize"
+if test "x$ac_cv_func_tcsetwinsize" = xyes
+then :
+  printf "%s\n" "#define HAVE_TCSETWINSIZE 1" >>confdefs.h
+
 fi
 ac_fn_c_check_func "$LINENO" "times" "ac_cv_func_times"
 if test "x$ac_cv_func_times" = xyes
index 982ff5e13425699c320f62fe8da39f16cd652e32..fe9306f461b65a93126639bd4aa027a24da0c673 100644 (file)
@@ -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 <http://www.gnu.org/licenses/>.
 
-AC_REVISION([for Bash 5.3, version 5.064])dnl
+AC_REVISION([for Bash 5.3, version 5.065])dnl
 
 define(bashvers, 5.3)
 define(relstatus, alpha)
@@ -870,7 +870,8 @@ AC_CHECK_FUNCS(bcopy bzero clock_gettime confstr faccessat fnmatch \
                getaddrinfo gethostbyname getservbyname getservent inet_aton \
                imaxdiv memmove pathconf putenv raise random regcomp regexec \
                setenv setlinebuf setlocale setvbuf siginterrupt strchr \
-               sysconf syslog tcgetattr times ttyname tzset unsetenv)
+               sysconf syslog tcgetattr tcgetwinsize tcsetwinsize \
+               times ttyname tzset unsetenv)
 
 AC_CHECK_FUNCS(vasprintf asprintf)
 AC_CHECK_FUNCS(isascii isblank isgraph isprint isspace isxdigit)
index 3dcecf21fba80c86f5ed14cea95fbcab983de1e9..1596eae1faf2913a0b30ab91ed40477854548e7b 100644 (file)
@@ -1453,7 +1453,8 @@ time_command (COMMAND *command, int asynchronous, int pipe_in, int pipe_out, str
     rv = execute_command_internal (command, asynchronous, pipe_in, pipe_out, fds_to_close);
   COPY_PROCENV (save_top_level, top_level);
 
-  command->flags = old_flags;
+  if (code == NOT_JUMPED)
+    command->flags = old_flags;
 
   /* If we're jumping in a different subshell environment than we started,
      don't bother printing timing stats, just keep longjmping back to the
@@ -2366,7 +2367,7 @@ coproc_setvars (struct coproc *cp)
        }
     }
 
-  if (v && (readonly_p (v) || noassign_p (v)))
+  if (v && ASSIGN_DISALLOWED (v, 0))
     {
       if (readonly_p (v))
        err_readonly (cp->c_name);
@@ -3040,7 +3041,7 @@ execute_for_command (FOR_COM *for_command)
       else
        v = bind_variable (identifier, list->word->word, 0);
 
-      if (v == 0 || readonly_p (v) || noassign_p (v))
+      if (v == 0 || ASSIGN_DISALLOWED (v, 0))
        {
          line_number = save_line_number;
          if (v && readonly_p (v) && interactive_shell == 0 && posixly_correct)
@@ -3213,6 +3214,21 @@ execute_arith_for_command (ARITH_FOR_COM *arith_for_command)
       expresult = eval_arith_for_expr (arith_for_command->test, &expok);
       line_number = save_lineno;
 
+      /* If the step or test expressions execute `break' or `continue' in a
+        nofork command substitution or by some other means, break the loop
+        here. */
+      if (breaking)
+       {
+         breaking--;
+         break;
+       }
+      if (continuing)
+       {
+         continuing--;
+         if (continuing)
+           break;
+       }
+
       if (expok == 0)
        break;
 
@@ -3534,7 +3550,7 @@ execute_select_command (SELECT_COM *select_command)
        }
 
       v = bind_variable (identifier, selection, 0);
-      if (v == 0 || readonly_p (v) || noassign_p (v))
+      if (v == 0 || ASSIGN_DISALLOWED (v, 0))
        {
          if (v && readonly_p (v) && interactive_shell == 0 && posixly_correct)
            {
@@ -6263,7 +6279,7 @@ execute_intern_function (WORD_DESC *name, FUNCTION_DEF *funcdef)
     }
 
   var = find_function (name->word);
-  if (var && (readonly_p (var) || noassign_p (var)))
+  if (var && ASSIGN_DISALLOWED (var, 0))
     {
       if (readonly_p (var))
        internal_error (_("%s: readonly function"), var->name);
diff --git a/expr.c b/expr.c
index f680012458f89bee050d3dc0c716718fc9194ffb..03ead0c450a6ea4e8894b9f9a2c48ee816316606 100644 (file)
--- a/expr.c
+++ b/expr.c
@@ -336,7 +336,7 @@ expr_bind_variable (const char *lhs, const char *rhs)
   aflags = 0;
 #endif
   v = bind_int_variable (lhs, rhs, aflags);
-  if (v && (readonly_p (v) || noassign_p (v)))
+  if (v && ASSIGN_DISALLOWED (v, 0))
     sh_longjmp (evalbuf, 1);   /* variable assignment error */
   stupidly_hack_special_variables (lhs);
 }
index f564a47f54d12e171366dabc069a95a5dc5dc805..cae21cdbdb7afda6689de4036f1d02ec0e474303 100644 (file)
@@ -77,6 +77,10 @@ extern int errno;
 #  include "colors.h"
 #endif
 
+#ifndef MIN
+#define MIN(x,y) (((x) < (y)) ? (x): (y))
+#endif
+
 typedef int QSFUNC (const void *, const void *);
 
 #ifdef HAVE_LSTAT
@@ -1355,6 +1359,7 @@ compute_lcd_of_matches (char **match_list, int matches, const char *text)
   int low;             /* Count of max-matched characters. */
   int lx;
   char *dtext;         /* dequoted TEXT, if needed */
+  size_t si1, si2;
   size_t len1, len2;
 #if defined (HANDLE_MULTIBYTE)
   int v;
@@ -1385,7 +1390,7 @@ compute_lcd_of_matches (char **match_list, int matches, const char *text)
       len1 = strlen (match_list[i]);
       len2 = strlen (match_list[i + 1]);
 
-      for (si = 0; (c1 = match_list[i][si]) && (c2 = match_list[i + 1][si]); si++)
+      for (si1 = si2 = 0; (c1 = match_list[i][si1]) && (c2 = match_list[i + 1][si2]); si1++,si2++)
        {
            if (_rl_completion_case_fold)
              {
@@ -1395,8 +1400,8 @@ compute_lcd_of_matches (char **match_list, int matches, const char *text)
 #if defined (HANDLE_MULTIBYTE)
            if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
              {
-               v1 = MBRTOWC (&wc1, match_list[i]+si, len1 - si, &ps1);
-               v2 = MBRTOWC (&wc2, match_list[i+1]+si, len2 - si, &ps2);
+               v1 = MBRTOWC (&wc1, match_list[i]+si1, len1 - si1, &ps1);
+               v2 = MBRTOWC (&wc2, match_list[i+1]+si2, len2 - si2, &ps2);
                if (MB_INVALIDCH (v1) || MB_INVALIDCH (v2))
                  {
                    if (c1 != c2)       /* do byte comparison */
@@ -1410,8 +1415,11 @@ compute_lcd_of_matches (char **match_list, int matches, const char *text)
                  }
                if (wc1 != wc2)
                  break;
-               else if (v1 > 1)
-                 si += v1 - 1;
+
+               if (v1 > 1)
+                 si1 += v1 - 1;
+               if (v2 > 1)
+                 si2 += v2 - 1;
              }
            else
 #endif
@@ -1419,6 +1427,7 @@ compute_lcd_of_matches (char **match_list, int matches, const char *text)
              break;
        }
 
+      si = MIN (si1, si2);     /* use shorter of matches of different length */
       if (low > si)
        low = si;
     }
index 5d512805e4ebd03fc20642b65835c029e7157040..bb5655d2afd30bd0d8417aa63ad38ddbb7dfff2f 100644 (file)
@@ -2011,9 +2011,7 @@ _rl_readstr_init (int pchar, int flags)
 
   cxt = _rl_rscxt_alloc (flags);
 
-  rl_maybe_replace_line ();
   _rl_saved_line_for_readstr = _rl_alloc_saved_line ();
-
   rl_undo_list = 0;
 
   rl_line_buffer[0] = 0;
index acae1b5a3de8e6f3f4724462c4d9ab12a3cd22fb..17f3f539af8e601eec273fb005581a68efdfcb29 100644 (file)
@@ -41,13 +41,16 @@ extern int errno;
 #  define ZBUFSIZ 4096
 #endif
 
-extern int executing_builtin;
+extern int executing_builtin, interrupt_state;
 
 extern void check_signals_and_traps (void);
 extern void check_signals (void);
 extern int signal_is_trapped (int);
 extern int read_builtin_timeout (int);
 
+/* Forward declarations */
+void zreset (void);
+
 /* Read LEN bytes from FD into BUF.  Retry the read on EINTR.  Any other
    error causes the loop to break. */
 ssize_t
@@ -66,7 +69,11 @@ zread (int fd, char *buf, size_t len)
       /* XXX - bash-5.0 */
       /* We check executing_builtin and run traps here for backwards compatibility */
       if (executing_builtin)
-       check_signals_and_traps ();     /* XXX - should it be check_signals()? */
+       {
+         if (interrupt_state)
+           zreset ();
+         check_signals_and_traps ();   /* XXX - should it be check_signals()? */
+       }
       else
        check_signals ();
       errno = t;
diff --git a/quit.h b/quit.h
index 44d9082837122889f81c7f42c724eca31cf43cca..318d6686b7f96f4707eefca4c0e1ef3e7575885c 100644 (file)
--- a/quit.h
+++ b/quit.h
@@ -83,4 +83,9 @@ do { \
     } \
 } while (0)
 
+#define ZRESET() \
+  do { \
+    if (interrupt_state) zreset (); \
+  } while (0)
+
 #endif /* _QUIT_H_ */
diff --git a/redir.c b/redir.c
index 37b470da71199df03eedb042a7d73c249cc99269..6e950f8469b300eeb584060f83053e3d00b8a552 100644 (file)
--- a/redir.c
+++ b/redir.c
@@ -1417,7 +1417,7 @@ redir_varassign (REDIRECT *redir, int fd)
 
   w = redir->redirector.filename;
   v = bind_var_to_int (w->word, fd, 0);
-  if (v == 0 || readonly_p (v) || noassign_p (v))
+  if (v == 0 || ASSIGN_DISALLOWED (v, 0))
     return BADVAR_REDIRECT;
 
   stupidly_hack_special_variables (w->word);
diff --git a/subst.c b/subst.c
index 3faa4068aba32c0a82855f8ba121c61930b53eff..929fabb26da177c6a4fdc13290d498976f6749ec 100644 (file)
--- a/subst.c
+++ b/subst.c
@@ -2295,7 +2295,7 @@ skip_to_delim (const char *string, int start, const char *delims, int flags)
            CQ_RETURN(si);
 
          if (string[i+1] == LPAREN)
-           temp = extract_delimited_string (string, &si, "$(", "(", ")", SX_NOALLOC|SX_COMMAND|completeflag); /* ) */
+           temp = extract_command_subst (string, &si, SX_NOALLOC|SX_COMMAND|completeflag);
          else
            temp = extract_dollar_brace_string (string, &si, 0, SX_NOALLOC|completeflag);
          CHECK_STRING_OVERRUN (i, si, slen, c);
@@ -3450,7 +3450,7 @@ do_compound_assignment (const char *name, char *value, int flags)
     {
       v = find_variable (name);                /* follows namerefs */
       newname = (v == 0) ? nameref_transform_name (name, flags) : v->name;
-      if (v && ((readonly_p (v) && (flags & ASS_FORCE) == 0) || noassign_p (v)))
+      if (v && ASSIGN_DISALLOWED (v, flags))
        {
          if (readonly_p (v))
            err_readonly (name);
@@ -3476,7 +3476,7 @@ do_compound_assignment (const char *name, char *value, int flags)
        v = 0;
       if (v == 0)
         v = find_global_variable (name);
-      if (v && ((readonly_p (v) && (flags & ASS_FORCE) == 0) || noassign_p (v)))
+      if (v && ASSIGN_DISALLOWED (v, flags))
        {
          if (readonly_p (v))
            err_readonly (name);
@@ -3502,7 +3502,7 @@ do_compound_assignment (const char *name, char *value, int flags)
   else
     {
       v = assign_array_from_string (name, value, flags);
-      if (v && ((readonly_p (v) && (flags & ASS_FORCE) == 0) || noassign_p (v)))
+      if (v && ASSIGN_DISALLOWED (v, flags))
        {
          if (readonly_p (v))
            err_readonly (name);
@@ -8172,7 +8172,7 @@ parameter_brace_expand_rhs (char *name, char *value,
 #endif /* ARRAY_VARS */
   v = bind_variable (vname, t1, 0);
 
-  if (v == 0 || readonly_p (v) || noassign_p (v))      /* expansion error  */
+  if (v == 0 || ASSIGN_DISALLOWED (v, 0))              /* expansion error */
     {
       if ((v == 0 || readonly_p (v)) && interactive_shell == 0 && posixly_correct)
        {
index 1f8b19fb57d1c176b9a711a9afe2fe333ec5d0cb..990438baaa9ab83978eb68083704a4098fb3ac51 100644 (file)
@@ -140,3 +140,7 @@ for ((j=;;)); do :; done
 echo X
 break
 echo Y
+
+# arithmetic for commands need to skip over command substitutions
+for (( $(case x in x) esac);; )); do break; done
+for (( ${ case x in x) esac; };; )); do break; done
index 84b30d936a6abc93f3197ffb2198af20fe1e1bf2..a64368e4a879db61b55356bedc298b9f916cb86b 100644 (file)
@@ -3126,7 +3126,7 @@ bind_variable_internal (const char *name, const char *value, HASH_TABLE *table,
     }
   else if (entry->assign_func) /* array vars have assign functions now */
     {
-      if ((readonly_p (entry) && (aflags & ASS_FORCE) == 0) || noassign_p (entry))
+      if (ASSIGN_DISALLOWED (entry, aflags))
        {
          if (readonly_p (entry))
            err_readonly (name_cell (entry));
@@ -3148,7 +3148,7 @@ bind_variable_internal (const char *name, const char *value, HASH_TABLE *table,
   else
     {
 assign_value:
-      if ((readonly_p (entry) && (aflags & ASS_FORCE) == 0) || noassign_p (entry))
+      if (ASSIGN_DISALLOWED (entry, aflags))
        {
          if (readonly_p (entry))
            err_readonly (name_cell (entry));
@@ -3581,8 +3581,8 @@ assign_in_env (const WORD_DESC *word, int flags)
        }
       else
         newname = name_cell (var);     /* no-op if not nameref */
-         
-      if (var && (readonly_p (var) || noassign_p (var)))
+
+      if (var && ASSIGN_DISALLOWED (var, 0))
        {
          if (readonly_p (var))
            err_readonly (name);
index ba13192514ff48c4e0a7c161373b7aac92c05e3c..fe8c3c23bca095126bff8ff2c4fec9e03270d3cc 100644 (file)
@@ -238,6 +238,10 @@ typedef struct _vlist {
 /* Special value for nameref with invalid value for creation or assignment */
 extern SHELL_VAR nameref_invalid_value;
 #define INVALID_NAMEREF_VALUE  (void *)&nameref_invalid_value
+
+/* Assignment statements */
+#define ASSIGN_DISALLOWED(v, f) \
+  ((readonly_p (v) && (f&ASS_FORCE) == 0) || noassign_p (v))
        
 /* Stuff for hacking variables. */
 typedef int sh_var_map_func_t (SHELL_VAR *);