Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: [bug] :P modifier and symlink loops



Bart Schaefer wrote on Thu, 24 Apr 2025 20:17 +00:00:
> On Thu, Apr 24, 2025 at 11:36 AM Mikael Magnusson <mikachu@xxxxxxxxx> wrote:
>>
>> > 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
⋮
> We could resolve the issue without adding back the xsymlnks call if we
> could tell that chrealpath has returned the exact same path it was
> given.

Is the attached patch correct?

It adds one string duplication, one string comparison, and a bit of
boilerplate to make sure we have memccpy() [sic].  (I wasn't sure if
that function could be assumed to be available, so I went ahead and
added a configure check and a fallback codepath.)

Cheers,

Daniel
diff --git a/Src/utils.c b/Src/utils.c
index 19fd61a..4ea7b8e 100644
--- a/Src/utils.c
+++ b/Src/utils.c
@@ -1003,11 +1003,23 @@ print_if_link(char *s, int all)
 		}
 	    }
 	} else {
-	    if (chrealpath(&s, 'P', 0)) {
+#ifdef HAVE_MEMCCPY
+	    char s_at_entry[PATH_MAX+1];
+	    if (!memccpy(s_at_entry, s, '\0', sizeof(s_at_entry))) {
+		DPUTS1(1, "path longer than PATH_MAX: %s", s);
+		s_at_entry[PATH_MAX] = '\0';
+	    }
+#else /* HAVE_MEMCCPY */
+	    char *s_at_entry = ztrdup(s);
+#endif /* HAVE_MEMCCPY */
+	    if (chrealpath(&s, 'P', 0) && strcmp(s, s_at_entry)) {
 		printf(" -> ");
 		zputs(*s ? s : "/", stdout);
 		zsfree(s);
 	    }
+#ifndef HAVE_MEMCCPY
+	    zsfree(s_at_entry);
+#endif /* !HAVE_MEMCCPY */
 	}
     }
 }
diff --git a/Test/B13whence.ztst b/Test/B13whence.ztst
index 3b35835..5132c2c 100644
--- a/Test/B13whence.ztst
+++ b/Test/B13whence.ztst
@@ -32,3 +32,7 @@
     whence -S flip || whence -S loop || whence -s flip || whence -s loop
   )
 1:whence deals with symlink loops gracefully
+
+ whence -s =sh(:P) | grep '.->' | wc -l
+0:(workers/53524) whence -s doesn't print arrows for symlink-free paths
+>0
diff --git a/configure.ac b/configure.ac
index ab368c9..13895bb 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1261,6 +1261,7 @@ AC_CHECK_FUNCS(strftime strptime mktime timelocal \
 	       initgroups \
 	       setuid seteuid setreuid setresuid setsid \
 	       setgid setegid setregid setresgid \
+	       memccpy \
 	       memcpy memmove strstr strerror strtoul \
 	       getrlimit getrusage \
 	       setlocale \


Messages sorted by: Reverse Date, Date, Thread, Author