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
--- 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 */