Re: [PATCH] Don't segfault when uniquifying hidden tied arrays

Philippe Altherr <[email protected]> Mon, 20 Jul 2026 15:15:58 +0200
Newsgroups gmane.comp.shells.zsh.devel
Message-ID <CAGdYchs4StAndjgG9aY1wTf8OvsaWnaJ5ONxRgr23QN6o3UuLQ@mail.gmail.com>
--000000000000b094b406570ab5c0
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

On Mon, Jul 20, 2026 at 7:55=E2=80=AFAM Bart Schaefer <schaefer@brasslanter=
n.com>
wrote:

> On Sun, Jul 19, 2026 at 7:28=E2=80=AFPM Philippe Altherr
> <[email protected]> wrote:
> >
> > - (Param) paramtab->getnode(paramtab, pm->ename))) {
> > - x =3D (*apm->gsu.a->getfn)(apm);
> > +    } else if (PM_TYPE(pm->node.flags) =3D=3D PM_SCALAR && pm->ename) =
{
> > + x =3D *(pm->node.flags & PM_SPECIAL
> > +      ? (char ***)pm->u.data
> > +      : ((struct tieddata *)pm->u.data)->arrptr);
>
> Just checking ... apm->gsu.a->getfn can return the static &nullarray
> to guarantee the result is never NULL.
>
> Are you confident that pm->u.data is never NULL or a pointer to NULL here=
?
>

pm->u.data is never NULL by constructions. Global special tied scalars like
PATH
<https://github.com/zsh-users/zsh/blob/3c0372aef88a6b7cc86f0902b1ba3f14a751=
18c9/Src/params.c#L406>
are
initialized with IPDEF8
<https://github.com/zsh-users/zsh/blob/3c0372aef88a6b7cc86f0902b1ba3f14a751=
18c9/Src/params.c#L401>,
which initializes u.data with a pointer to the underlying variable.
Similarly, module defined tied scalars, like WATCH
<https://github.com/zsh-users/zsh/blob/3c0372aef88a6b7cc86f0902b1ba3f14a751=
18c9/Src/Modules/watch.c#L699>,
have their u.data initialized
<https://github.com/zsh-users/zsh/blob/3c0372aef88a6b7cc86f0902b1ba3f14a751=
18c9/Src/module.c#L1079>with
a pointer to the underlying variable
<https://github.com/zsh-users/zsh/blob/3c0372aef88a6b7cc86f0902b1ba3f14a751=
18c9/Src/module.c#L1079>
. User defined tied scalars initialize u.data with an instance of tieddata
<https://github.com/zsh-users/zsh/blob/3c0372aef88a6b7cc86f0902b1ba3f14a751=
18c9/Src/builtin.c#L2561>
whose arrptr points to the u.arr of the tied array
<https://github.com/zsh-users/zsh/blob/3c0372aef88a6b7cc86f0902b1ba3f14a751=
18c9/Src/builtin.c#L2558>
.

The function colonarrgetfn
<https://github.com/zsh-users/zsh/blob/3c0372aef88a6b7cc86f0902b1ba3f14a751=
18c9/Src/params.c#L4275>
used
by special tied scalars assumes that u.data contains a non-NULL char***.

The function tiedarrgetfn
<https://github.com/zsh-users/zsh/blob/3c0372aef88a6b7cc86f0902b1ba3f14a751=
18c9/Src/params.c#L4302>
used
by user defined tied scalars assumes that u.data contains a non-NULL struct
tieddata * whose arrptr field contains a non-NULL char***.

While pm->u.data is never NULL, the value assigned to x may be NULL but
that's fine, then the code that follows simply does nothing; the function
uniqarray
<https://github.com/zsh-users/zsh/blob/3c0372aef88a6b7cc86f0902b1ba3f14a751=
18c9/Src/params.c#L4468>
immediately
returns if its parameter is NULL.

Philippe

--000000000000b094b406570ab5c0
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><div dir=3D"ltr"><span style=3D"background-color:transpare=
nt">On Mon, Jul 20, 2026 at 7:55=E2=80=AFAM Bart Schaefer &lt;<a href=3D"ma=
ilto:[email protected]">[email protected]</a>&gt; wrote:</s=
pan></div><div class=3D"gmail_quote gmail_quote_container"><blockquote clas=
s=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid r=
gb(204,204,204);padding-left:1ex">On Sun, Jul 19, 2026 at 7:28=E2=80=AFPM P=
hilippe Altherr<br>
&lt;<a href=3D"mailto:[email protected]" target=3D"_blank">philipp=
[email protected]</a>&gt; wrote:<br>
&gt;<br>
&gt; - (Param) paramtab-&gt;getnode(paramtab, pm-&gt;ename))) {<br>
&gt; - x =3D (*apm-&gt;gsu.a-&gt;getfn)(apm);<br>
&gt; +=C2=A0 =C2=A0 } else if (PM_TYPE(pm-&gt;node.flags) =3D=3D PM_SCALAR =
&amp;&amp; pm-&gt;ename) {<br>
&gt; + x =3D *(pm-&gt;node.flags &amp; PM_SPECIAL<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 ? (char ***)pm-&gt;u.data<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 : ((struct tieddata *)pm-&gt;u.data)-&gt;arrptr)=
;<br>
<br>
Just checking ... apm-&gt;gsu.a-&gt;getfn can return the static &amp;nullar=
ray<br>
to guarantee the result is never NULL.<br>
<br>
Are you confident that pm-&gt;u.data is never NULL or a pointer to NULL her=
e?<br></blockquote><div><br></div><div>pm-&gt;u.data is never NULL by const=
ructions. Global special tied scalars like <a href=3D"https://github.com/zs=
h-users/zsh/blob/3c0372aef88a6b7cc86f0902b1ba3f14a75118c9/Src/params.c#L406=
">PATH</a>=C2=A0are initialized with <a href=3D"https://github.com/zsh-user=
s/zsh/blob/3c0372aef88a6b7cc86f0902b1ba3f14a75118c9/Src/params.c#L401">IPDE=
F8</a>, which initializes u.data with a pointer to the underlying variable.=
 Similarly, module defined tied scalars, like <a href=3D"https://github.com=
/zsh-users/zsh/blob/3c0372aef88a6b7cc86f0902b1ba3f14a75118c9/Src/Modules/wa=
tch.c#L699">WATCH</a>, have their <a href=3D"https://github.com/zsh-users/z=
sh/blob/3c0372aef88a6b7cc86f0902b1ba3f14a75118c9/Src/module.c#L1079">u.data=
 initialized=C2=A0</a><span style=3D"background-color:transparent"><a href=
=3D"https://github.com/zsh-users/zsh/blob/3c0372aef88a6b7cc86f0902b1ba3f14a=
75118c9/Src/module.c#L1079">with a pointer to the underlying variable</a>.=
=C2=A0</span><span style=3D"background-color:transparent">User defined tied=
 scalars </span><a href=3D"https://github.com/zsh-users/zsh/blob/3c0372aef8=
8a6b7cc86f0902b1ba3f14a75118c9/Src/builtin.c#L2561" style=3D"background-col=
or:transparent">initialize  u.data with an instance of tieddata</a><span st=
yle=3D"background-color:transparent"> whose=C2=A0</span><a href=3D"https://=
github.com/zsh-users/zsh/blob/3c0372aef88a6b7cc86f0902b1ba3f14a75118c9/Src/=
builtin.c#L2558" style=3D"background-color:transparent">arrptr points to th=
e u.arr of the tied array</a><span style=3D"background-color:transparent">.=
</span></div><div><span style=3D"background-color:transparent"><br></span><=
/div><div><span style=3D"background-color:transparent">The function=C2=A0<a=
 href=3D"https://github.com/zsh-users/zsh/blob/3c0372aef88a6b7cc86f0902b1ba=
3f14a75118c9/Src/params.c#L4275">colonarrgetfn</a>=C2=A0used by special tie=
d scalars assumes that u.data contains a non-NULL char***.</span></div><div=
><span style=3D"background-color:transparent"><br></span></div><div><span s=
tyle=3D"background-color:transparent">The function=C2=A0<a href=3D"https://=
github.com/zsh-users/zsh/blob/3c0372aef88a6b7cc86f0902b1ba3f14a75118c9/Src/=
params.c#L4302">tiedarrgetfn</a>=C2=A0used by user defined tied scalars ass=
umes that u.data contains a non-NULL=C2=A0</span><span style=3D"background-=
color:transparent">struct tieddata * whose arrptr field contains a non-NULL=
 char***.</span></div><div><span style=3D"background-color:transparent"><br=
></span></div><div><span style=3D"background-color:transparent">While pm-&g=
t;u.data is never NULL, the value assigned to x may be NULL but that&#39;s =
fine, then the code that follows simply does nothing; the function=C2=A0</s=
pan><span style=3D"background-color:transparent"><a href=3D"https://github.=
com/zsh-users/zsh/blob/3c0372aef88a6b7cc86f0902b1ba3f14a75118c9/Src/params.=
c#L4468">uniqarray</a>=C2=A0immediately returns if its parameter is NULL.</=
span></div><div><span style=3D"background-color:transparent"><br></span></d=
iv><div><span style=3D"background-color:transparent">Philippe</span></div><=
div><span style=3D"background-color:transparent"><br></span></div></div></d=
iv>

--000000000000b094b406570ab5c0--