]> git.ipfire.org Git - thirdparty/bash.git/commitdiff
fix for crash without arrays built in; allow some job status changes while the jobs...
authorChet Ramey <chet.ramey@case.edu>
Mon, 6 May 2024 15:15:17 +0000 (11:15 -0400)
committerChet Ramey <chet.ramey@case.edu>
Mon, 6 May 2024 15:15:17 +0000 (11:15 -0400)
13 files changed:
CWRU/CWRU.chlog
MANIFEST
config-top.h
doc/bash.1
execute_cmd.c
jobs.c
jobs.h
nojobs.c
parse.y
shell.c
subst.c
support/siglen.c [new file with mode: 0644]
tests/jobs.right

index 03280dce42f79271dbf551cc36618a1a22df4942..c4cb56211179edae6a5d7a72bf0d65d51468630f 100644 (file)
@@ -9277,3 +9277,53 @@ subst.c
        - function_substitute: make sure we unbind the local REPLY we created
          at the current (fake) context
          From a report by Koichi Murase <myoga.murase@gmail.com>
+
+                                  4/30
+                                  ----
+
+subst.c
+       - expand_arrayref: fix crash from freeing memory that's only allocated
+         and initialized if ARRAY_VARS is defined
+         Report and patch from Henrik Lindström <henrik@lxm.se>
+
+jobs.h,jobs.c
+       - JLIST_POSIX: new format argument for pretty_print_job; implements
+         POSIX requirement that jobs display the status of all background
+         jobs and all jobs the user hasn't been notified about (unused yet)
+       - JLIST_BGONLY: new format argument for pretty_print_job; restricts
+         output to background jobs only (unused yet)
+
+jobs.c,jobs.h,execute_cmd.c,subst.c
+       - freeze_jobs_list: now takes an int argument with the new value of
+         jobs_list_frozen; prep for having different values with different
+         meanings; changed callers
+
+jobs.c
+       - wait_for_any_job: return right away if jobs_list_frozen > 0; allow
+         job status changes (e.g., J_NOTIFIED) if jobs_list_frozen < 0; use
+         this instead of testing executing_funsub directly
+       - notify_and_cleanup: allow notification and status change if
+         jobs_list_frozen < 0; don't delete any dead jobs
+       - should_notify: takes a job index and returns 1 if the shell would
+         notify the user about it, given the current job state
+       - pretty_print_job: if the jobs list is frozen, only print status
+         about jobs for which the shell would notify users (by calling
+         should_notify())
+
+subst.c
+       - function_substitute: freeze the jobs list with value -1 so jobs
+         can change status and possibly inhibit printing by `jobs'
+
+                                   5/2
+                                   ---
+jobs.c
+       - notify_and_cleanup: allow job notifications if an interactive shell
+         is running a trap (interactive == 0 && interactive_shell && running_trap)
+         Fixes report by Koichi Murase <myoga.murase@gmail.com> on 11/14/2022
+       - print_pipeline: don't print an extra space before the pipeline; push
+         that into pretty_print_job; print the space after the pid if we
+         print one
+
+jobs.h
+       - LONGEST_SIGNAL_DESC: update to 27 (macos SIGPROF). This changes the
+         test output
index 5c51c945da7534756274430a64ee7f05e769a848..0d2f5f065cb5b0f6b48569b6f9702a895826a7cf 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -728,6 +728,7 @@ support/mkinstalldirs       f       755
 support/mkversion.sh   f       755
 support/mksignames.c   f
 support/signames.c     f
+support/siglen.c       f
 support/bashbug.sh     f
 support/bashbug.sh.in  f
 support/man2html.c     f
index 40e599fcd28881e4a001659d5f4ec4d99ae61740..b6e73c4b74ec80deee74d576dcfed18371df18d0 100644 (file)
@@ -47,7 +47,7 @@
 
 /* Define DONT_REPORT_SIGTERM if you don't want to see `Terminated' message
    when a job exits due to SIGTERM, since that's the default signal sent
-   by the kill builtin. */
+   by the kill builtin. Only effective for non-interactive shells. */
 #define DONT_REPORT_SIGTERM
 
 /* Define DONT_REPORT_BROKEN_PIPE_WRITE_ERRORS if you don't want builtins
index 233eda531587d213eb1b9783e292b4e7e7514f2b..0e21f409299f15549e31cae57448272cfc07b056 100644 (file)
 .if \n(zY=1 .ig zY
 .TH BASH 1 "2024 April 23" "GNU Bash 5.3"
 .\"
-.\" There's some problem with having a `@'
-.\" in a tagged paragraph with the BSD man macros.
-.\" It has to do with `@' appearing in the }1 macro.
-.\" This is a problem on 4.3 BSD and Ultrix, but Sun
-.\" appears to have fixed it.
-.\" If you're seeing the characters
-.\" `@u-3p' appearing before the lines reading
-.\" `possible-hostname-completions
-.\" and `complete-hostname' down in READLINE,
-.\" then uncomment this redefinition.
-.\"
-.\" .de }1
-.\" .ds ]X \&\\*(]B\\
-.\" .nr )E 0
-.\" .if !"\\$1"" .nr )I \\$1n
-.\" .}f
-.\" .ll \\n(LLu
-.\" .in \\n()Ru+\\n(INu+\\n()Iu
-.\" .ti \\n(INu
-.\" .ie !\\n()Iu+\\n()Ru-\w\a\\*(]X\au-3p \{\\*(]X
-.\" .br\}
-.\" .el \\*(]X\h\a|\\n()Iu+\\n()Ru\a\c
-.\" .}f
-.\" ..
-.\"
 .ie \n(.g \{\
 .ds ' \(aq
 .ds " \(dq
index 8600de20b833e4ce0a5da4b6863df635be164d96..5a9477a438b89dbeb8db44b1e991cdda1ef9e4ec 100644 (file)
@@ -2695,7 +2695,7 @@ execute_pipeline (COMMAND *command, int asynchronous, int pipe_in, int pipe_out,
          prev = NO_PIPE;
          add_unwind_protect (uw_restore_stdin, (void *) (intptr_t) lstdin);
          lastpipe_flag = 1;
-         old_frozen = freeze_jobs_list ();
+         old_frozen = freeze_jobs_list (1);
          lastpipe_jid = stop_pipeline (0, (COMMAND *)NULL);    /* XXX */
          add_unwind_protect (uw_lastpipe_cleanup, (void *) (intptr_t) old_frozen);
 #if defined (JOB_CONTROL)
@@ -2831,6 +2831,10 @@ execute_connection (COMMAND *command, int asynchronous, int pipe_in, int pipe_ou
 #endif
 
       QUIT;
+#if defined (JOB_CONTROL)
+      if (command->value.Connection->connector == ';' && job_control && interactive)
+        notify_and_cleanup ();
+#endif
       optimize_connection_fork (command);                      /* XXX */
       exec_result = execute_command_internal (command->value.Connection->second,
                                      asynchronous, pipe_in, pipe_out,
diff --git a/jobs.c b/jobs.c
index dbc07a020086ed0972b996d2e05e000b5fd0b1b1..c0c9cb2b400e5bba9199836d6b7a68a813b1bc08 100644 (file)
--- a/jobs.c
+++ b/jobs.c
@@ -337,10 +337,11 @@ static SigHandler *old_cont = (SigHandler *)SIG_DFL;
 /* A place to temporarily save the current pipeline. */
 static struct pipeline_saver *saved_pipeline;
 
-/* Set this to non-zero whenever you don't want the jobs list to change at
+/* Set this to 1 whenever you don't want the jobs list to change at
    all: no jobs deleted and no status change notifications.  This is used,
    for example, when executing SIGCHLD traps, which may run arbitrary
-   commands. */
+   commands. Set to -1 if you allow status change notifications but no
+   jobs deleted. 0 means everything is allowed. */
 static int jobs_list_frozen;
 
 static char retcode_name_buffer[64];
@@ -1905,19 +1906,26 @@ printable_job_status (int j, PROCESS *p, int format)
 /* This is the way to print out information on a job if you
    know the index.  FORMAT is:
 
-    JLIST_NORMAL)   [1]+ Running          emacs
+    JLIST_STANDARD)   [1]+ Running        emacs
     JLIST_LONG  )   [1]+ 2378 Running      emacs
     -1   )   [1]+ 2378       emacs
 
-    JLIST_NORMAL)   [1]+ Stopped          ls | more
+    JLIST_STANDARD)   [1]+ Stopped        ls | more
     JLIST_LONG  )   [1]+ 2369 Stopped      ls
                         2367       | more
     JLIST_PID_ONLY)
        Just list the pid of the process group leader (really
        the process group).
     JLIST_CHANGED_ONLY)
-       Use format JLIST_NORMAL, but list only jobs about which
-       the user has not been notified. */
+       Use format JLIST_STANDARD, but list only jobs about which
+       the user has not been notified.
+    JLIST_POSIX)
+       Use format JLIST_STANDARD, list all background jobs, running
+       and stopped, plus jobs about which the user has not been
+       notified (that would be notified)
+    JLIST_BGONLY)
+       Use format JLIST_STANDARD, but restrict output to background
+       jobs only. */
 
 /* Print status for pipeline P.  If JOB_INDEX is >= 0, it is the index into
    the JOBS array corresponding to this pipeline.  FORMAT is as described
@@ -1945,9 +1953,14 @@ print_pipeline (PROCESS *p, int job_index, int format, FILE *stream)
        fprintf (stream, format ? "     " : " |");
 
       if (format != JLIST_STANDARD)
-       fprintf (stream, "%5ld", (long)p->pid);
+       {
+         fprintf (stream, "%5ld", (long)p->pid);
+         if (p == first)
+           fprintf (stream, " ");
+       }
 
-      fprintf (stream, " ");
+      if (p != first)
+       fprintf (stream, " ");
 
       if (format > -1 && job_index >= 0)
        {
@@ -2021,6 +2034,29 @@ print_pipeline (PROCESS *p, int job_index, int format, FILE *stream)
   fflush (stream);
 }
 
+/* We want to print information about a job if it's running or terminated in
+   the background, if it's stopped, or if it was a foreground job terminated
+   due to a signal that we don't ignore (SIGINT and possibly SIGTERM and
+   SIGPIPE). If we change this, change the conditions in notify_of_job_status()
+   so they stay consistent.
+
+   This is for use by the jobs builtin. */
+
+static int
+should_notify (int job)
+{
+  /* Background jobs, stopped jobs whether they were in the foreground or
+     background. */
+  if ((IS_FOREGROUND (job) == 0) || STOPPED (job))
+    return 1;
+
+  /* Foreground job killed by a signal we report on. */
+  if (DEADJOB (job) && IS_FOREGROUND (job) && job_killed_by_signal (job))
+    return 1;
+
+  return 0;            /* catch-all */  
+}
+
 /* Print information to STREAM about jobs[JOB_INDEX] according to FORMAT.
    Must be called with SIGCHLD blocked or queued with queue_sigchld */
 static void
@@ -2028,6 +2064,13 @@ pretty_print_job (int job_index, int format, FILE *stream)
 {
   register PROCESS *p;
 
+  /* If the jobs list is frozen, skip jobs we would remove and not report on */
+  if (jobs_list_frozen && should_notify (job_index) == 0)
+    return;
+
+  if (format == JLIST_BGONLY && IS_FOREGROUND (job_index))
+    return;
+
   /* Format only pid information about the process group leader? */
   if (format == JLIST_PID_ONLY)
     {
@@ -2041,6 +2084,12 @@ pretty_print_job (int job_index, int format, FILE *stream)
        return;
       format = JLIST_STANDARD;
     }
+  else if (format == JLIST_POSIX)
+    {
+      if (IS_FOREGROUND (job_index) && IS_NOTIFIED (job_index))
+       return;
+      format = JLIST_STANDARD;
+    }
 
   if (format != JLIST_NONINTERACTIVE)
     fprintf (stream, "[%d]%c ", job_index + 1,
@@ -2050,8 +2099,10 @@ pretty_print_job (int job_index, int format, FILE *stream)
   if (format == JLIST_NONINTERACTIVE)
     format = JLIST_LONG;
 
-  p = jobs[job_index]->pipe;
+  if (format == JLIST_STANDARD)
+    fprintf (stream, "%c", ' ');               /* used to be in print_pipeline */
 
+  p = jobs[job_index]->pipe;
   print_pipeline (p, job_index, format, stream);
 
   /* We have printed information about this job.  When the job's
@@ -3275,7 +3326,7 @@ wait_for_any_job (int flags, struct procstat *ps)
   sigset_t set, oset;
 
   /* Allow funsubs to run this, but don't remove jobs from the jobs table. */
-  if (jobs_list_frozen && executing_funsub == 0)
+  if (jobs_list_frozen > 0)
     return -1;
 
   /* First see if there are any unnotified dead jobs that we can report on */
@@ -3297,13 +3348,11 @@ return_job:
          if (jobs_list_frozen == 0)            /* must be running a funsub to get here */
            {
              notify_of_job_status ();          /* XXX */
-#if 1 /* kre@munnari.oz.au 01/30/2024 */
+
+             /* kre@munnari.oz.au 01/30/2024 */
              delete_job (i, posixly_correct ? DEL_NOBGPID : 0);
-#else
-             delete_job (i, 0);
-#endif
            }
-         else
+         else /* if (jobs_list_frozen < 0) */  /* status changes only */
            jobs[i]->flags |= J_NOTIFIED;       /* clean up later */
 #if defined (COPROCESS_SUPPORT)
          coproc_reap ();
@@ -3371,12 +3420,15 @@ return_job:
 void
 notify_and_cleanup (void)
 {
-  if (jobs_list_frozen)
+  if (jobs_list_frozen > 0)
     return;
 
-  if (interactive || interactive_shell == 0 || sourcelevel)
+  if (interactive || interactive_shell == 0 || sourcelevel || (interactive_shell && running_trap))
     notify_of_job_status ();
 
+  if (jobs_list_frozen < 0)
+    return;            /* status changes only */
+
   cleanup_dead_jobs ();
 }
 
@@ -4357,14 +4409,19 @@ notify_of_job_status (void)
                  if (termsig && WIFSIGNALED (s) && termsig != SIGINT && termsig != SIGPIPE)
 #endif
                    {
+#if 0
                      fprintf (stderr, "%s", j_strsignal (termsig));
 
                      if (WIFCORED (s))
                        fprintf (stderr, _(" (core dumped)"));
 
                      fprintf (stderr, "\n");
+#else
+                     print_pipeline (jobs[job]->pipe, job, JLIST_STANDARD, stderr);
+#endif
                    }
-                 /* foreground jobs that exit cleanly */
+                 /* foreground jobs that exit cleanly or due to a signal we
+                    don't report on */
                  jobs[job]->flags |= J_NOTIFIED;
                }
              else if (job_control)
@@ -4970,12 +5027,12 @@ itrace("mark_dead_jobs_as_notified: child_max = %d ndead = %d ndeadproc = %d", j
 /* Here to allow other parts of the shell (like the trap stuff) to
    freeze and unfreeze the jobs list. */
 int
-freeze_jobs_list (void)
+freeze_jobs_list (int n)
 {
   int o;
 
   o = jobs_list_frozen;
-  jobs_list_frozen = 1;
+  jobs_list_frozen = n;
   return o;
 }
 
diff --git a/jobs.h b/jobs.h
index 2ec52f59c1e465ee0fc60d9bda3a1ede5d183390..31c4fd32d0672f0904878c3639a8a25dbceb3974 100644 (file)
--- a/jobs.h
+++ b/jobs.h
 #define JLIST_PID_ONLY      2
 #define JLIST_CHANGED_ONLY   3
 #define JLIST_NONINTERACTIVE 4
+#define JLIST_POSIX         5
+#define JLIST_BGONLY        6
 
-/* I looked it up.  For pretty_print_job ().  The real answer is 24. */
-#define LONGEST_SIGNAL_DESC 24
+/* I looked it up.  For pretty_print_job ().  The real answer is 27
+   (macOS SIGPROF) but the makefile or configure can override it. */
+#ifndef LONGEST_SIGNAL_DESC
+#  define LONGEST_SIGNAL_DESC 27
+#endif
 
 /* Defines for the wait_for_* functions and for the wait builtin to use */
 #define JWAIT_PERROR           (1 << 0)
@@ -301,7 +306,7 @@ extern int give_terminal_to (pid_t, int);
 
 extern void run_sigchld_trap (int);
 
-extern int freeze_jobs_list (void);
+extern int freeze_jobs_list (int);
 extern int unfreeze_jobs_list (void);
 extern void set_jobs_list_frozen (int);
 extern int jobs_list_frozen_status (void);
index ad10b0622df1a6a74008d64644933d4ec267f442..c429b6e3398dbe9409a47491ee817d78e52cc429 100644 (file)
--- a/nojobs.c
+++ b/nojobs.c
@@ -1010,7 +1010,7 @@ describe_pid (pid_t pid)
 }
 
 int
-freeze_jobs_list (void)
+freeze_jobs_list (int n)
 {
   return 0;
 }
diff --git a/parse.y b/parse.y
index 575dc642d84b895dbdbaf488516b70973cc47a1e..b347fbb5ea2c423856756056c505ce4580228e13 100644 (file)
--- a/parse.y
+++ b/parse.y
@@ -7242,9 +7242,11 @@ flush_parser_state (sh_parser_state_t *ps)
   FREE (ps->token_state);
   ps->token_state = 0;
 
+#if defined (ARRAY_VARS)
   if (ps->pipestatus)
     array_dispose (ps->pipestatus);
   ps->pipestatus = 0;
+#endif
 
   /* We want to free the saved token and leave the current token for error
      reporting and cleanup. */
diff --git a/shell.c b/shell.c
index 3592e48b66bc654ce032f8293ad7d34e29199550..84ac5c4ed6e9dac7163e8936ebd9b928c6a9b3dd 100644 (file)
--- a/shell.c
+++ b/shell.c
@@ -448,7 +448,7 @@ main (int argc, char **argv, char **env)
 
   /* Fix for the `infinite process creation' bug when running shell scripts
      from startup files on System V. */
-  login_shell = make_login_shell = 0;
+  login_shell = make_login_shell = su_shell = 0;
 
   /* If this shell has already been run, then reinitialize it to a
      vanilla state. */
@@ -1996,7 +1996,7 @@ shell_reinitialize (void)
   no_rc = no_profile = 1;
 
   /* Things that get 0. */
-  login_shell = make_login_shell = executing = 0;
+  login_shell = make_login_shell = su_shell = executing = 0;
   debugging = debugging_mode = 0;
   do_version = line_number = last_command_exit_value = 0;
   forced_interactive = interactive_shell = interactive = 0;
diff --git a/subst.c b/subst.c
index e84deb9c51e975d61821a26d0e6dea5196d4ca73..175cd5c36dbb628c5d55ee47eb39d78971096154 100644 (file)
--- a/subst.c
+++ b/subst.c
@@ -7088,8 +7088,10 @@ function_substitute (char *string, int quoted, int flags)
        add_unwind_protect (uw_unbind_localvar, "REPLY");
     }
 
-  old_frozen = freeze_jobs_list ();
+#if 1  /* TAG:bash-5.3 myoga.murase@gmail.com 04/30/2024 */
+  old_frozen = freeze_jobs_list (-1);
   add_unwind_protect (uw_lastpipe_cleanup, (void *) (intptr_t) old_frozen);
+#endif
 
 #if defined (JOB_CONTROL)
   unwind_protect_var (pipeline_pgrp);
@@ -7806,7 +7808,9 @@ expand_arrayref:
 
          temp = quote_var_value (temp, quoted, pflags);
 
+#if defined (ARRAY_VARS)
          FREE (tt);
+#endif
        }
       else
        temp = (char *)NULL;
diff --git a/support/siglen.c b/support/siglen.c
new file mode 100644 (file)
index 0000000..56a5761
--- /dev/null
@@ -0,0 +1,28 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <signal.h>
+
+int
+main(int argc, char **argv)
+{
+       int     i, l, longest, verb;
+       size_t  len;
+       char    *msg;
+
+       verb = (argc > 1 && argv[1] && strcmp (argv[1], "-l") == 0);
+
+       longest = 0;
+       for (i = 0; i < NSIG; i++) {
+               msg = strsignal (i);
+               len = msg ? strlen (msg) : 0;
+               l = len;
+               if (msg && verb)
+                       printf ("%d\t%s\n", l, msg);
+               if (l > longest)
+                       longest = l;
+       }
+       printf ("%d\n", longest);
+       exit (0);
+}
index 173743aea501b60256367f53edecfb38b74b3f96..f8037bc834433f277628af2489ae0cf65376f915 100644 (file)
@@ -16,17 +16,17 @@ Waiting for job 6
 job 6 returns 0
 Waiting for job 7
 job 7 returns 0
-[1]   Running                 sleep 2 &
-[2]   Running                 sleep 2 &
-[3]   Running                 sleep 2 &
-[4]-  Running                 sleep 2 &
-[5]+  Running                 ( sleep 2; exit 4 ) &
+[1]   Running                    sleep 2 &
+[2]   Running                    sleep 2 &
+[3]   Running                    sleep 2 &
+[4]-  Running                    sleep 2 &
+[5]+  Running                    ( sleep 2; exit 4 ) &
 4
 0
 i killed it
 12
-[1]-  Running                 sleep 20 &
-[3]+  Running                 sleep 20 &
+[1]-  Running                    sleep 20 &
+[3]+  Running                    sleep 20 &
 5: ok 1
 ./jobs5.sub: line 40: wait: %8: no such job
 2: ok 2
@@ -53,7 +53,7 @@ async list wait for child
 forked
 wait-when-no-children
 posix jobs output
-[1]+  Done                    sleep 1
+[1]+  Done                       sleep 1
 wait-for-job
 ./jobs.tests: line 96: wait: %2: no such job
 127
@@ -84,36 +84,36 @@ wait-for-non-child
 ./jobs.tests: line 150: wait: pid 1 is not a child of this shell
 127
 3 -- 1 2 3 -- 1 - 2 - 3
-[1]   Running                 sleep 300 &
-[2]-  Running                 sleep 350 &
-[3]+  Running                 sleep 400 &
+[1]   Running                    sleep 300 &
+[2]-  Running                    sleep 350 &
+[3]+  Running                    sleep 400 &
 running jobs:
-[1]   Running                 sleep 300 &
-[2]-  Running                 sleep 350 &
-[3]+  Running                 sleep 400 &
+[1]   Running                    sleep 300 &
+[2]-  Running                    sleep 350 &
+[3]+  Running                    sleep 400 &
 ./jobs.tests: line 167: kill: %4: no such job
 ./jobs.tests: line 169: jobs: %4: no such job
 current job:
-[3]+  Running                 sleep 400 &
+[3]+  Running                    sleep 400 &
 previous job:
-[2]-  Running                 sleep 350 &
+[2]-  Running                    sleep 350 &
 after kill -STOP
 running jobs:
-[1]   Running                 sleep 300 &
-[3]-  Running                 sleep 400 &
+[1]   Running                    sleep 300 &
+[3]-  Running                    sleep 400 &
 stopped jobs:
-[2]+  Stopped                 sleep 350
+[2]+  Stopped                    sleep 350
 after disown
-[2]+  Stopped                 sleep 350
-[3]-  Running                 sleep 400 &
+[2]+  Stopped                    sleep 350
+[3]-  Running                    sleep 400 &
 running jobs:
-[3]-  Running                 sleep 400 &
+[3]-  Running                    sleep 400 &
 stopped jobs:
-[2]+  Stopped                 sleep 350
+[2]+  Stopped                    sleep 350
 after kill -s CONT
 running jobs:
-[2]+  Running                 sleep 350 &
-[3]-  Running                 sleep 400 &
+[2]+  Running                    sleep 350 &
+[3]-  Running                    sleep 400 &
 stopped jobs:
 after kill -STOP, backgrounding %3:
 [3]+ sleep 400 &