[Pkg-zsh-devel] Bug#1030606: bad job control on suspended shell function

Zefram zefram at fysh.org
Sun Feb 5 15:21:38 GMT 2023


Package: zsh
Version: 5.8-6+deb11u1
Severity: normal
Tags: patch

zsh screws up the way it displays job status if a job consists of a
shell function that got suspended after it was started:

% t0 () { sleep 1000; }
% t0
^Zzsh: suspended
[1]  + suspended
% echo foo
foo
[1]  + suspended
% :
[1]  + suspended
% jobs
[1]  + suspended
[1]  + suspended
[1]  + suspended
%

Observe that the job's status is redundantly reported before each
prompt is issued, and an extra time when executing the "jobs" builtin.
(The triple output around "jobs" consists of a redundant output before
doing the real work of "jobs", the requested job listing, and then another
redundant output before the next prompt.)  Also observe that the command
being run in the job is never reported.  By contrast, here's what correct
job control looks like:

% sleep 1000
^Z
zsh: suspended  sleep 1000
% echo foo
foo
% :
% jobs
[1]  + suspended  sleep 1000

This bug arises in situations where the job's command was originally
run as part of the shell process (as is the case with a shell function),
that command spawned an external process, and the job then got suspended,
forcing the shell to fork off a subprocess to embody the job.  The parent
shell manages the complicated process relationships that result by means
of a hidden subjob.  When called upon to display the state of the original
job, it shows the original job's number, but then substitutes in the
subjob for everything else that it does.  The command text isn't displayed
because the subjob doesn't have that data.  The frequent redundant
display happens because the original job is marked as needing reporting,
so reporting is triggered, but after reporting it is the subjob that
gets that flag cleared, so it is reported again at the next opportunity.

There are complicated things that could be done to fix these problems
while reporting the subjob status.  But, having examined various
combinations of job statuses that can occur, I think that actually it
was a mistake to report on the subjob in place of the original job.
The attached patch therefore fixes this bug in a very simple way, by
deleting the logic that switches focus to the subjob.  With this patch
in place, the above test case produces this pleasing output:

% t0 () { sleep 1000; }
% t0
^Zzsh: suspended  t0
% echo foo
foo
% :
% jobs
[1]  + suspended (signal)  t0
%

-zefram
-------------- next part --------------
--- zsh-5.8.orig/Src/jobs.c	2020-01-05 17:59:57.000000000 +0000
+++ zsh-5.8/Src/jobs.c	2023-02-05 14:36:37.640874940 +0000
@@ -1077,22 +1077,6 @@
 	lng = !!isset(LONGLISTJOBS);
     }
 
-    if (jn->stat & STAT_SUPERJOB &&
-	jn->other)
-    {
-	Job sjn = &jobtab[jn->other];
-	if (sjn->procs || sjn->auxprocs)
-	{
-	    /*
-	     * A subjob still has process, which must finish before
-	     * further execution of the superjob, which the user wants to
-	     * know about.  So report the status of the subjob as if it
-	     * were the user-visible superjob.
-	     */
-	    jn = sjn;
-	}
-    }
-
 /* find length of longest signame, check to see */
 /* if we really need to print this job          */
 


More information about the Pkg-zsh-devel mailing list