Re: zsh segfault bug from 5.9.1-1 onwards

Mikael Magnusson <[email protected]>
Newsgroups gmane.comp.shells.zsh.devel
Message-ID <CAHYJk3R2uNBOCJ-dxnirJ7gaW54LQNo=dwn8LvhFpj4NOzJm+Q@mail.gmail.com>
On Fri, Aug 7, 2026 at 9:25 AM Châu Trác Thịnh <[email protected]> wrote:
>
> I'm on Arch Linux, and a script of mine started to segfault after updating from 5.9-6 to 5.9.1-1.
>
> Minimal reproduction: run the following
> ```
> (echo 1 | cat & (echo 2))
> ```
>
> There's no segfault when:
>
> Reverting to 5.9-6
> removing either of the parenthesis
> removing any command in the chain (replacing them can still segfault; my original code is quite different)

After break fork and fiddling with set follow-fork-mode I managed to
follow the correct child,
Thread 4.1 "zsh" received signal SIGSEGV, Segmentation fault.
0x0000000000462cde in havefiles () at jobs.c:1620
1620    peekfirst(jobtab[i].filelist)) {
(gdb) bt
#0  0x0000000000462cde in havefiles () at jobs.c:1620
#1  0x00000000004394b0 in execcmd_exec (state=0x7ffcf7998710,
eparams=0x7ffcf79979c0,
    input=0, output=0, how=18, last1=1, close_if_forked=-1) at exec.c:3719
#2  0x0000000000434bf1 in execpline2 (state=0x7ffcf7998710, pcode=707,
how=18, input=0,
    output=0, last1=1) at exec.c:2070
#3  0x0000000000433834 in execpline (state=0x7ffcf7998710,
slcode=10242, how=18, last1=1)
    at exec.c:1795
(gdb) p *jobtab[i].filelist
$2 = {list = {first = 0x0, last = 0x22af360, flags = 0}, node = {next = 0x0,
    prev = 0x22af360, dat = 0x0}}

As we can see here, first is NULL, and peekfirst does
->list.first->dat which crashes. The problem was introduced in
zw/51404: Nullify filelist after deleting (fix segfault)
d3edf318306e37d2d96. The problem isn't that it nullifies the filelist,
but how it checks for that later.

I think this is the fix:

diff --git i/Src/jobs.c w/Src/jobs.c
index 657d62ea0b..fef3c708e5 100644
--- i/Src/jobs.c
+++ w/Src/jobs.c
@@ -1617,7 +1617,7 @@ havefiles(void)

     for (i = 1; i <= maxjob; i++)
        if (jobtab[i].stat && jobtab[i].filelist &&
-           peekfirst(jobtab[i].filelist)) {
+           nonempty(jobtab[i].filelist)) {
            return 1;
        }
     return 0;

Which instead just checks if ->list.first == NULL.

-- 
Mikael Magnusson
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.