]> git.ipfire.org Git - thirdparty/bash.git/commitdiff
fix for %P in TIMEFORMAT; make updating variables that aren't subject to allexport...
authorChet Ramey <chet.ramey@case.edu>
Mon, 6 Oct 2025 19:29:41 +0000 (15:29 -0400)
committerChet Ramey <chet.ramey@case.edu>
Mon, 6 Oct 2025 19:29:41 +0000 (15:29 -0400)
CWRU/CWRU.chlog
builtins/read.def
builtins/set.def
builtins/shopt.def
doc/bash.1
doc/bashref.texi
execute_cmd.c
include/typemax.h
parse.y
subst.h
variables.c

index 4114d6770d5cab1ce462df94e952c1719b2d18f4..e7c491311a16998f11d96d1f31bbe5425b77a035 100644 (file)
@@ -11862,3 +11862,52 @@ parse.y
        - reset_parser: reset shell_eof_token to 0, rely on callers to restore
          it if they need to
          Report from Grisha Levit <grishalevit@gmail.com>
+
+execute_cmd.c
+       - print_formatted_time: when processing %P, sum_frac should be in
+         microseconds; missed when making max precision 6 back in 6/2023
+         Report from pourko2@tutamail.com
+
+                                  9/30
+                                  ----
+subst.h
+       - ASS_NOEXPORT: don't export the variable being assigned even if
+         `allexport' is enabled
+
+builtins/set.def
+       - set_shellopts: pass ASS_NOEXPORT so we don't have to mess with
+         unsetting the export attribute
+
+builtins/shopt.def
+       - set_bashopts: pass ASS_NOEXPORT so we don't have to mess with
+         unsetting the export attribute
+
+variables.c
+       - bind_variable_internal,bind_variable_value: if ASS_NOEXPORT is set in
+         the flags argument, don't export the variable even if `allexport'
+         (mark_modified_vars) is set.
+         Patch from Martin D Kealey <martin@kurahaupo.gen.nz>
+
+                                  10/1
+                                  ----
+include/typemax.h
+       - PTRDIFF_MAX: add default max value for ptrdiff_t if the system
+         doesn't provide one
+
+parse.y
+       - SIZE_MAX -> PTRDIFF_MAX to avoid spurious compiler warning
+         Patch from Martin D Kealey <martin@kurahaupo.gen.nz> and
+         Grisha Levit <grishalevit@gmail.com>
+
+execute_cmd.c
+       - time_command: don't bother with time zone info in gettimeofday()
+       - time_command: don't bother trying to execute a null command in
+         posix mode, since we just want timing information since the shell
+         started
+
+                                  10/3
+                                  ----
+builtins/read.def
+       - read_builtin: don't use i as a return value for functions and then
+         as an index into input_string without resetting it
+         Report and patch from Grisha Levit <grishalevit@gmail.com>
index 4ad36325ddb4ea3c5f680c9146037d7515561367..cb0d3053879a556c39f786083abb67a128d7865a 100644 (file)
@@ -622,8 +622,7 @@ read_builtin (WORD_LIST *list)
          termsave.attrs = ttattrs;
 
          ttset = ttattrs;        
-         i = silent ? ttfd_cbreak (fd, &ttset) : ttfd_onechar (fd, &ttset);
-         if (i < 0)
+         if ((silent ? ttfd_cbreak (fd, &ttset) : ttfd_onechar (fd, &ttset)) < 0)
            sh_ttyerror (1);
          tty_modified = 1;
          add_unwind_protect (uw_ttyrestore, &termsave);
@@ -639,8 +638,7 @@ read_builtin (WORD_LIST *list)
       termsave.attrs = ttattrs;
 
       ttset = ttattrs;
-      i = ttfd_noecho (fd, &ttset);                    /* ttnoecho (); */
-      if (i < 0)
+      if (ttfd_noecho (fd, &ttset) < 0)
        sh_ttyerror (1);
 
       tty_modified = 1;
index 13630c22df706f130183f56a3d7d85b722990135..e8597d4a022f1fbe0461a8091441878aec26b22a 100644 (file)
@@ -532,7 +532,7 @@ set_shellopts (void)
 {
   char *value;
   char tflag[N_O_OPTIONS];
-  int i, *ip, exported;
+  int i, *ip;
   size_t vsize, vptr;
   SHELL_VAR *v;
 
@@ -571,21 +571,12 @@ set_shellopts (void)
     vptr--;                    /* cut off trailing colon */
   value[vptr] = '\0';
 
-  v = find_variable ("SHELLOPTS");
+  /* ASS_FORCE so we don't have to temporarily turn off readonly; ASS_NOEXPORT
+     so we don't have to work around allexport. */
+  v = bind_variable ("SHELLOPTS", value, ASS_FORCE|ASS_NOEXPORT);
 
-  /* Note whether or not the variable was exported so we can adjust after the
-     assignment. */
-  exported = v ? exported_p (v) : 0;
-
-  /* ASS_FORCE so we don't have to temporarily turn off readonly */
-  v = bind_variable ("SHELLOPTS", value, ASS_FORCE);
-
-  /* Turn the read-only attribute back on, and turn off the export attribute
-     if it was set implicitly by mark_modified_vars and SHELLOPTS was not
-     exported before we bound the new value. */
+  /* Turn the read-only attribute back on. */
   VSETATTR (v, att_readonly);
-  if (mark_modified_vars && exported == 0 && exported_p (v))
-    VUNSETATTR (v, att_exported);
 
   free (value);
 }
index cf6f6be1265249b8b6326dc186485c2465132305..6ecc087f8272491783d91e1b8d944810b72a381d 100644 (file)
@@ -823,7 +823,7 @@ set_bashopts (void)
 {
   char *value;
   char tflag[N_SHOPT_OPTIONS];
-  int i, exported;
+  int i;
   size_t vsize, vptr;
   SHELL_VAR *v;
 
@@ -853,21 +853,14 @@ set_bashopts (void)
     vptr--;                    /* cut off trailing colon */
   value[vptr] = '\0';
 
-  v = find_variable ("BASHOPTS");
-
-  /* Note whether or not the variable was exported so we can adjust after the
-     assignment. */
-  exported = v ? exported_p (v) : 0;
-
-  /* ASS_FORCE so we don't have to temporarily turn off readonly */
-  v = bind_variable ("BASHOPTS", value, ASS_FORCE);
+  /* ASS_FORCE so we don't have to temporarily turn off readonly; ASS_NOEXPORT
+     so we don't have to work around allexport. */
+  v = bind_variable ("BASHOPTS", value, ASS_FORCE|ASS_NOEXPORT);
 
   /* Turn the read-only attribute back on, and turn off the export attribute
      if it was set implicitly by mark_modified_vars and SHELLOPTS was not
      exported before we bound the new value. */
   VSETATTR (v, att_readonly);
-  if (mark_modified_vars && exported == 0 && exported_p (v))
-    VUNSETATTR (v, att_exported);
 
   free (value);
 }
index f82c130c2c1d6bc41a45482aee3d756be78020de..c68729126081717d91b03c84ee38c8e01bf7cf38 100644 (file)
@@ -2513,6 +2513,10 @@ A filename whose suffix matches one of the entries in
 is excluded from the list of matched filenames.
 A sample value is
 .Q .o:\*~ .
+Since tilde expansion takes place after
+.Q :
+in assignment statements,
+make sure to quote assignments appropriately to avoid it as appropriate.
 .TP
 .B FUNCNEST
 If set to a numeric value greater than 0, defines a maximum function
index 0ac623d1bbe9c4f1ec4b98c47794f79b8bd79006..600c802865a5d7727de0c1d3169fe012cfe955d7 100644 (file)
@@ -7174,8 +7174,13 @@ A colon-separated list of suffixes to ignore when performing
 filename completion.
 A filename whose suffix matches one of the entries in 
 @env{FIGNORE}
-is excluded from the list of matched filenames.  A sample
-value is @samp{.o:~}
+is excluded from the list of matched filenames.
+A sample value is
+@samp{.o:~}.
+Since tilde expansion takes place after
+@samp{:}
+in assignment statements,
+make sure to quote assignments appropriately to avoid it as appropriate.
 
 @item FUNCNAME
 An array variable containing the names of all shell functions
index 3a1c169edbb0c93c96366281af783c0fdedbdfc4..789a8b09a12e0d5dc17a9c72631b3b45eff948af 100644 (file)
@@ -1408,7 +1408,7 @@ print_formatted_time (FILE *fp, char *format,
            cpu = 10000;
 #endif
          sum = cpu / 100;
-         sum_frac = (cpu % 100) * 10;
+         sum_frac = (cpu % 100) * 10000;       /* convert to microseconds */
          len = mkfmt (ts, 2, 0, sum, sum_frac);
          RESIZE_MALLOCED_BUFFER (str, sindex, len, ssize, 64);
          strcpy (str + sindex, ts);
@@ -1468,9 +1468,6 @@ time_command (COMMAND *command, int asynchronous, int pipe_in, int pipe_out, str
 #if defined (HAVE_GETRUSAGE) && defined (HAVE_GETTIMEOFDAY)
   struct timeval real, user, sys;
   struct timeval before, after;
-#  if defined (HAVE_STRUCT_TIMEZONE)
-  struct timezone dtz;                         /* posix doesn't define this */
-#  endif
   struct rusage selfb, selfa, kidsb, kidsa;    /* a = after, b = before */
 #else
 #  if defined (HAVE_TIMES)
@@ -1479,24 +1476,28 @@ time_command (COMMAND *command, int asynchronous, int pipe_in, int pipe_out, str
 #  endif
 #endif
 
+  rv = EXECUTION_SUCCESS;              /* suppress uninitialized use warnings */
+
+  rs = us = ss = 0;
+  rsf = usf = ssf = 0;
+  cpu = 0;
+
+  old_subshell = subshell_environment;
+  posix_time = command && (command->flags & CMD_TIME_POSIX);
+  nullcmd = (command == 0) || (command->type == cm_simple && command->value.Simple->words == 0 && command->value.Simple->redirects == 0);
+
 #if defined (HAVE_GETRUSAGE) && defined (HAVE_GETTIMEOFDAY)
-#  if defined (HAVE_STRUCT_TIMEZONE)
-  gettimeofday (&before, &dtz);
-#  else
-  gettimeofday (&before, NULL);
-#  endif /* !HAVE_STRUCT_TIMEZONE */
   getrusage (RUSAGE_SELF, &selfb);
   getrusage (RUSAGE_CHILDREN, &kidsb);
+  gettimeofday (&before, NULL);
 #else
 #  if defined (HAVE_TIMES)
   tbefore = times (&before);
 #  endif
 #endif
 
-  old_subshell = subshell_environment;
-  posix_time = command && (command->flags & CMD_TIME_POSIX);
-
-  nullcmd = (command == 0) || (command->type == cm_simple && command->value.Simple->words == 0 && command->value.Simple->redirects == 0);
+  /* In posix mode, `time' without argument is equivalent to `times', but
+     obeys TIMEFORMAT. This is from POSIX interp 267 */
   if (posixly_correct && nullcmd)
     {
 #if defined (HAVE_GETRUSAGE)
@@ -1508,35 +1509,27 @@ time_command (COMMAND *command, int asynchronous, int pipe_in, int pipe_out, str
       tbefore = shell_start_time * get_clk_tck ();
 #endif
     }
+  else
+    {
+      old_flags = command->flags;
+      COPY_PROCENV (top_level, save_top_level);
+      command->flags &= ~(CMD_TIME_PIPELINE|CMD_TIME_POSIX);
+      code = setjmp_nosigs (top_level);
+      if (code == NOT_JUMPED)
+       rv = execute_command_internal (command, asynchronous, pipe_in, pipe_out, fds_to_close);
+      COPY_PROCENV (save_top_level, top_level);
+      if (code == NOT_JUMPED)
+       command->flags = old_flags;
 
-  rv = EXECUTION_SUCCESS;              /* suppress uninitialized use warnings */
-  old_flags = command->flags;
-  COPY_PROCENV (top_level, save_top_level);
-  command->flags &= ~(CMD_TIME_PIPELINE|CMD_TIME_POSIX);
-  code = setjmp_nosigs (top_level);
-  if (code == NOT_JUMPED)
-    rv = execute_command_internal (command, asynchronous, pipe_in, pipe_out, fds_to_close);
-  COPY_PROCENV (save_top_level, top_level);
-
-  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
-     original top level. */
-  if (code != NOT_JUMPED && subshell_environment && subshell_environment != old_subshell)
-    sh_longjmp (top_level, code);
-
-  rs = us = ss = 0;
-  rsf = usf = ssf = 0;
-  cpu = 0;
+      /* If we're jumping in a different subshell environment than we started,
+        don't bother printing timing stats, just keep longjmping back to the
+        original top level. */
+      if (code != NOT_JUMPED && subshell_environment && subshell_environment != old_subshell)
+       sh_longjmp (top_level, code);
+    }
 
 #if defined (HAVE_GETRUSAGE) && defined (HAVE_GETTIMEOFDAY)
-#  if defined (HAVE_STRUCT_TIMEZONE)
-  gettimeofday (&after, &dtz);
-#  else
   gettimeofday (&after, NULL);
-#  endif /* !HAVE_STRUCT_TIMEZONE */
   getrusage (RUSAGE_SELF, &selfa);
   getrusage (RUSAGE_CHILDREN, &kidsa);
 
index e3b98f472ab5564f3be095e68d90da655c7e123e..467a4ac8be4d2f40568294a0c0d086d162fd36c9 100644 (file)
@@ -119,6 +119,10 @@ static const unsigned long long int maxquad = ULLONG_MAX;
 #  define SIZE_MAX     ((size_t) ~(size_t)0)
 #endif
 
+#ifndef PTRDIFF_MAX
+#  define PTRDIFF_MAX  TYPE_MAXIMUM(ptrdiff_t)
+#endif
+
 #ifndef sh_imaxabs
 #  define sh_imaxabs(x)        (((x) >= 0) ? (x) : -(x))
 #endif
diff --git a/parse.y b/parse.y
index 615c3fe026a25c8f740ad273500904807a0e508a..ab042dafb00723a24b56977921960db9764c5627 100644 (file)
--- a/parse.y
+++ b/parse.y
@@ -47,7 +47,7 @@
 
 #include "shell.h"
 #include "execute_cmd.h"
-#include "typemax.h"           /* SIZE_MAX if needed */
+#include "typemax.h"           /* PTRDIFF_MAX if needed */
 #include "trap.h"
 #include "flags.h"
 #include "parser.h"
@@ -2579,21 +2579,21 @@ shell_getc (int remove_quoted_newline)
          /* If we can't put 256 bytes more into the buffer, allocate
             everything we can and fill it as full as we can. */
          /* XXX - we ignore rest of line using `truncating' flag */
-         if (shell_input_line_size > (SIZE_MAX - 256))
+         if (shell_input_line_size > (PTRDIFF_MAX - 256))
            {
              size_t n;
 
-             n = SIZE_MAX - i; /* how much more can we put into the buffer? */
+             n = PTRDIFF_MAX - i;      /* how much more can we put into the buffer? */
              if (n <= 2)       /* we have to save 1 for the newline added below */
                {
                  if (truncating == 0)
-                   internal_warning(_("shell_getc: shell_input_line_size (%zu) exceeds SIZE_MAX (%lu): line truncated"), shell_input_line_size, (unsigned long)SIZE_MAX);
+                   internal_warning(_("shell_getc: shell_input_line_size (%zu) exceeds PTRDIFF_MAX (%lu): line truncated"), shell_input_line_size, (unsigned long)PTRDIFF_MAX);
                  shell_input_line[i] = '\0';
                  truncating = 1;
                }
-             if (shell_input_line_size < SIZE_MAX)
+             if (shell_input_line_size < PTRDIFF_MAX)
                {
-                 shell_input_line_size = SIZE_MAX;
+                 shell_input_line_size = PTRDIFF_MAX;
                  shell_input_line = xrealloc (shell_input_line, shell_input_line_size);
                }
            }
@@ -2735,7 +2735,7 @@ shell_getc (int remove_quoted_newline)
         not already end in an EOF character.  */
       if (shell_input_line_terminator != EOF && shell_input_line_terminator != READERR)
        {
-         if (shell_input_line_size + 3 < SIZE_MAX && (shell_input_line_len+3 > shell_input_line_size))
+         if (shell_input_line_size + 3 < PTRDIFF_MAX && (shell_input_line_len+3 > shell_input_line_size))
            shell_input_line = (char *)xrealloc (shell_input_line,
                                        1 + (shell_input_line_size += 2));
 
diff --git a/subst.h b/subst.h
index b412c66a585e7b14fbeb7e878a41531f3a17afa7..c9f155a8b62938a3e1eadd0f452ba2849dcaa854 100644 (file)
--- a/subst.h
+++ b/subst.h
@@ -45,7 +45,7 @@
 
 /* Flag values controlling how assignment statements are treated. */
 #define ASS_APPEND     0x0001  /* a+=b */
-#define ASS_MKLOCAL    0x0002
+#define ASS_MKLOCAL    0x0002  /* make a local variable */
 #define ASS_MKASSOC    0x0004
 #define ASS_MKGLOBAL   0x0008  /* force global assignment */
 #define ASS_NAMEREF    0x0010  /* assigning to nameref variable */
@@ -59,6 +59,7 @@
 #define ASS_ONEWORD    0x1000  /* don't check array subscripts, assume higher level has done that */
 #define ASS_NOTEMPENV  0x2000  /* don't assign into temporary environment */
 #define ASS_XTRACE     0x4000  /* print trace after compound assignment expansion */
+#define ASS_NOEXPORT   0x8000  /* don't export even if allexport is set */
 
 /* Flags for the string extraction functions. */
 #define SX_NOALLOC     0x0001  /* just skip; don't return substring */
index 2e418323080be5d4eedd0c9679e08c0c6e986f65..27fec3269082c23a09c342bcd8cca42fa673b2b8 100644 (file)
@@ -3166,7 +3166,7 @@ assign_value:
          INVALIDATE_EXPORTSTR (entry);
          optimized_assignment (entry, value, aflags);
 
-         if (mark_modified_vars)
+         if (mark_modified_vars && (aflags & ASS_NOEXPORT) == 0)
            VSETATTR (entry, att_exported);
 
          if (exported_p (entry))
@@ -3208,7 +3208,7 @@ assign_value:
        }
     }
 
-  if (mark_modified_vars)
+  if (mark_modified_vars && (aflags & ASS_NOEXPORT) == 0)
     VSETATTR (entry, att_exported);
 
   if (exported_p (entry))
@@ -3363,7 +3363,7 @@ bind_variable_value (SHELL_VAR *var, char *value, int aflags)
 
   INVALIDATE_EXPORTSTR (var);
 
-  if (mark_modified_vars)
+  if (mark_modified_vars && (aflags & ASS_NOEXPORT) == 0)
     VSETATTR (var, att_exported);
 
   if (exported_p (var))