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')
>
>
>
>
>