On Mon, Nov 2, 2026 at 1:57 PM Bruno Haible via GNU coreutils General
Discussion <[email protected]> wrote:

> Pádraig Brady wrote:
> > > In this case, when confstr (_CS_PATH) is longer than expected,
> > > I would prefer
> > >    - either an abort(),
>
> Recall: abort() is the preferred way for a programmer to say "if this
> situation occurs, I made a mistake, and I want to be notified".
>
> > Best not do that in a lib I think.
>
> Oh, that's the rule that I heard 25 years ago, when working on X11. libX11
> had no single call to abort(). And was libX11 reliable, or was it buggy?
> It was buggy, because when an application never crashes via abort(), only
> via "bad event" or so, users have no way to produce useful bug reports.
>
> GNU libiconv calls abort() in 173 places, and GNU libunistring in 220
> places.
> This provides enough incentive for a user to report a malfunction, and
> then I fix the bug. It doesn't happen often, though: only once in a couple
> of years.
>
> So, I'll use abort() here too.
>
> > >    - or a 'struct string_buffer', so that we don't use heap allocation
> > >      in the normal case.
> > We could use heap allocation only in the edge case where 256 is not
> enough,
>
> Yes, but this would be extra code for a hypothetical case that never occurs
> in practice. Because in all cases I've seen (except maybe macOS and
> NetBSD),
> confstr(_CS_PATH) returns a static literal string from libc:
>
> glibc:
>         static const char cs_path[] = CS_PATH;
>         string = cs_path;
>         string_len = sizeof (cs_path);
>
> musl:
>                 s = "/bin:/usr/bin";
>
> macOS:
> #define _PATH_STDPATH   "/usr/bin:/bin:/usr/sbin:/sbin"
>                 mib[0] = CTL_USER;
>                 mib[1] = USER_CS_PATH;
>                 if (sysctl(mib, 2, NULL, &tlen, NULL, 0) == -1)
>                         return (CONFSTR_ERR_RET);
>                 if (len != 0 && buf != NULL) {
>                         if ((p = malloc(tlen)) == NULL)
>                                 return (CONFSTR_ERR_RET);
>                         if (sysctl(mib, 2, p, &tlen, NULL, 0) == -1) {
>
> FreeBSD:
> #define _PATH_STDPATH   "/usr/bin:/bin:/usr/sbin:/sbin"
>                 p = _PATH_STDPATH;
>
> NetBSD:
> #define _PATH_STDPATH \
>
> "/usr/bin:/bin:/usr/sbin:/sbin:/usr/pkg/bin:/usr/pkg/sbin:/usr/local/bin:/usr/local/sbin"
>                 mib[0] = CTL_USER;
>                 mib[1] = USER_CS_PATH;
>                 if (sysctl(mib, 2, NULL, &tlen, NULL, 0) == -1)
>                         return 0;
>                 if (len != 0 && buf != NULL) {
>                         if ((p = malloc(tlen)) == NULL)
>                                 return 0;
>                         if (sysctl(mib, 2, p, &tlen, NULL, 0) == -1) {
>
> OpenBSD:
> #define _PATH_STDPATH
>  "/usr/bin:/bin:/usr/sbin:/sbin:/usr/X11R6/bin:/usr/local/bin:/usr/local/sbin"
>                 return (strlcpy(buf, _PATH_STDPATH, len) + 1);
>
> Solaris OpenIndiana:
>                 if (__xpg6 & _C99SUSv3_XPG6_sysconf_version)
>                         path = "/usr/xpg6/bin:/usr/xpg4/bin:/usr/ccs/bin:"
>                             "/usr/bin:/opt/SUNWspro/bin";
>                 else
>                         path = "/usr/xpg4/bin:/usr/ccs/bin:/usr/bin:"
>                             "/opt/SUNWspro/bin";
>
> Cygwin:
>   {ls ("/bin:/usr/bin")},               /* _CS_PATH */
>
> > or even xmalloca(), though I'd keep it as simple as possible for this
> > extreme edge case.
>
> xmalloca() would be essentially the same approach as the string-buffer
> approach.
>
> > If confstr returns 0, then we could use the glibc default of
> "/bin:/usr/bin"
> > or maybe just return NULL, as it's also an extreme edge case.
>

isn't this what _PATH_DEFPATH is for? bionic (android) doesn't support
_CS_PATH (or, indeed, confstr() at all) but does have  the BSD
_PATH_DEFPATH. looks like glibc has it too.


> This too is a hypothetical case. All known confstr() implementations
> support _CS_PATH.
>
> So, here's the patch that I will apply.
>
> diff --git a/lib/findprog-in.c b/lib/findprog-in.c
> index d937f7c834..1cc833316a 100644
> --- a/lib/findprog-in.c
> +++ b/lib/findprog-in.c
> @@ -223,9 +223,15 @@ find_in_given_path (const char *progname, const char
> *path,
>           dependent.  On POSIX systems, it is confstr (_CS_PATH).  */
>        #if HAVE_CONFSTR
>        int ret = confstr (_CS_PATH, default_path, sizeof (default_path));
> -      if (ret == 0 || ret > sizeof (default_path))
> +      if (ret == 0)
> +        /* The platform has confstr(), but it does not support _CS_PATH.
> */
> +        abort ();
> +      if (ret > sizeof (default_path))
> +        /* MAX_DEFAULT_PATH_SIZE is too small.  Increase it.  */
> +        abort ();
> +      #else /* native Windows, Android, Minix */
> +      default_path[0] = '\0';
>        #endif
> -        default_path[0] = '\0';
>        path = default_path;
>      }
>
> diff --git a/lib/findprog.c b/lib/findprog.c
> index 2d321dc0d9..63264bd159 100644
> --- a/lib/findprog.c
> +++ b/lib/findprog.c
> @@ -77,9 +77,15 @@ find_in_path (const char *progname)
>           dependent.  On POSIX systems, it is confstr (_CS_PATH).  */
>        #if HAVE_CONFSTR
>        int ret = confstr (_CS_PATH, default_path, sizeof (default_path));
> -      if (ret == 0 || ret > sizeof (default_path))
> +      if (ret == 0)
> +        /* The platform has confstr(), but it does not support _CS_PATH.
> */
> +        abort ();
> +      if (ret > sizeof (default_path))
> +        /* MAX_DEFAULT_PATH_SIZE is too small.  Increase it.  */
> +        abort ();
> +      #else /* native Windows, Android, Minix */
> +      default_path[0] = '\0';
>        #endif
> -        default_path[0] = '\0';
>        path = default_path;
>      }
>    if (*path == '\0')
>
>
>
>
>

Reply via email to