Zsh Mailing List Archive
Messages sorted by:
Reverse Date,
Date,
Thread,
Author
Re: [bug] :P modifier and symlink loops
- X-seq: zsh-workers 53505
- From: Mikael Magnusson <mikachu@xxxxxxxxx>
- To: Daniel Shahaf <d.s@xxxxxxxxxxxxxxxxxx>
- Cc: Stephane Chazelas <stephane.chazelas@xxxxxxxxx>, Zsh hackers list <zsh-workers@xxxxxxx>
- Subject: Re: [bug] :P modifier and symlink loops
- Date: Thu, 24 Apr 2025 20:19:19 +0200
- Archived-at: <https://zsh.org/workers/53505>
- In-reply-to: <20200321195048.7c49a291@tarpaulin.shahaf.local2>
- List-id: <zsh-workers.zsh.org>
- References: <20200111170047.ifjsdd5lfeksqyaa@chaz.gmail.com> <20200201175740.lma5dxgwufk6fpeg@chazelas.org> <20200202081021.7c8aab22@tarpaulin.shahaf.local2> <20200321195048.7c49a291@tarpaulin.shahaf.local2>
On Sat, Mar 21, 2020 at 8:51 PM Daniel Shahaf <d.s@xxxxxxxxxxxxxxxxxx> wrote:
>
> Daniel Shahaf wrote on Sun, 02 Feb 2020 08:10 +0000:
> > Stephane Chazelas wrote on Sat, 01 Feb 2020 17:57 +0000:
> > > Ping:
> >
> > Thanks for the ping. I've added this to Etc/BUGS so we don't forget
> > it. I worked on :P before, so I've added this to my list to
> > investigate further, but I don't know when I'll get to it.
> >
> > > 2020-01-11 17:00:47 +0000, Stephane Chazelas:
> > > Hi,
> > >
> > > I've got the feeling it's been discussed before, but could not
> > > find it in the archives.
> > >
> > > $ ln -s loop /tmp/
> > > $ f=/tmp/loop strace ~/install/cvs/zsh/Src/zsh -c '$f:P'
> > > [...]
> > > readlink("/tmp/loop", "loop", 4096) = 4
> > > readlink("/tmp/loop", "loop", 4096) = 4
> > > [...]
> > > readlink("/tmp/loop", "loop", 4096) = 4
> > > readlink("/tmp/loop", "loop", 4096) = 4
> > > --- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR,
> > > si_addr=0x7ffec7a345e0} ---
> > > +++ killed by SIGSEGV +++
> > >
> > > possibly stack overflow caused by unbound recursion or buffer
> > > overflow on /tmp/loop/loop... but the bigger question is what to
> > > do here.
> > >
> > > The ELOOP problem is usually addressed by giving up after an
> > > arbitrary number of symlinks has been resolved (regardless of
> > > whether there is indeed a loop or not) in the lookup of the
> > > file, but here $f:P *has* to expand to something, so what should
> > > that be?
> > >
> > > For instance, for
> > >
> > > cd /
> > > file=bin/../tmp/loop/../foo/.. above?
> > >
> > > The only thing I can think of is expand to:
> > >
> > > /tmp/loop/../foo/..
> > >
> > > (maybe done by first doing a stat(the-file); if it returns
> > > ELOOP, do a stat() at each stage of the resolution and give up
> > > on the first ELOOP).
> > >
> > > Any other idea?
> >
> > The postcondition of :P is "no dot or dot-dot components and no symlinks".
> >
> > When the loop is on the last path component (as in ${${:-/tmp/loop}:P}
> > and ${${:-/tmp/trap}:P} after «ln -s loop /tmp/trap») we could still print
> > a path to the loop symlink that meets the postcondition, except for the loop
> > symlink in the last path component.
> >
> > However, in ${${:-"/tmp/loop/../foo"}} we can't meet the postcondition.
> > I think our options are either to throw an exception, like a glob with
> > no matches does, or to keep the additional components verbatim, as you
> > suggest.
> >
> > Intuitively I lean towards the first option. We aren't a CGI script,
> > where PATH_INFO is to be expected. If we can't return a path without
> > dot and dot-dot components and without symlinks, we should raise an
> > error rather than continue silently. However, I'm open to alternatives.
> >
> > I think the first option could be implemented along the lines of:
> >
> > 1. Call realpath($arg).
> > 2. If it returns ELOOP, call realpath(${arg:h}) and append "/${arg:t}".
> > 3. Otherwise, throw an exception (i.e., set errflag).
>
> Patch series attached.
>
> I ended up implementing the second option — keeping the trailing
> components verbatim — for several reasons:
>
> 1. It's actually documented this way for :P. (xsymlink() has other
> callers too, but I didn't check whether any of them specifically relied
> on this behaviour.)
>
> 2. After I made the code use the realpath() wrapper function,
> chabspath(), rather than xsymlinks() (plural), that's the behaviour
> I observed, and I didn't go out of my way to change it.
>
> I suppose we could revisit :P's behaviour on symlink loops with
> trailing components after the loop, but in the meantime, this at least
> fixes the segfault.
>
> WDYT?
>
> Cheers,
>
> Daniel
Patch six in this series breaks whence -s, I guess it is not a very
common usecase since nobody complained until now.
Expected:
% Src/zsh -c 'which -s git'
/usr/bin/git
Actual:
% Src/zsh -c 'which -s git'
/usr/bin/git -> /usr/bin/git
Reverting the patch seems to resolve the issue, but I'm not sure what
the intent of the change was in the first place, the patch has no
explanation for it. The series talks about symlink loops, but a
symlink loop is effectively a broken symlink, and does not seem to be
found by 'which' at all (with the patch reverted):
% ln -s foo ~/bin/bar
% ln -s bar ~/bin/foo
% Src/zsh -c 'which -s foo'
foo not found
I know that Daniel isn't very active anymore, but if anyone else has
any thoughts?
--
Mikael Magnusson
Messages sorted by:
Reverse Date,
Date,
Thread,
Author