Hi Collin,
> In the find_in_given_path function, there are the following lines:
>
> if (path == NULL)
> /* If PATH is not set, the default search path is implementation
> dependent.
> In practice, it is treated like an empty PATH. */
> path = "";
>
> That isn't true on GNU/Linux, FreeBSD, and Solaris at least, where an
> unset PATH searches the default path specified by
> pathconf (_CS_PATH, ...) and an empty PATH searches the current working
> directory.
Indeed, I confirm your finding, by running the attached program 'foo.c'
under 'strace -ff'.
So, I was mistaken about what an unset PATH environment variable means.
> Perhaps the default to _CS_PATH I put here is better placed
> in the Gnulib function? It has been in POSIX for a long time [1].
>
> [1] https://pubs.opengroup.org/onlinepubs/9799919799/functions/confstr.html
Yes. Although the behaviour of find_in_given_path has been specified
for many years, I doubt that anyone would rely on this detail. It's
better to change it to follow POSIX's interpretation of a null PATH.
Done through the attached patches.
Nothing changes for platforms without confstr (native Windows, Android, Minix).
Bruno
#include <stdlib.h>
#include <unistd.h>
#include <spawn.h>
extern char **environ;
int main ()
{
//setenv ("PATH", "", 1); // only the current directory
//unsetenv ("PATH"); // only /bin:/usr/bin, from glibc/sysdeps/unix/confstr.h, confstr (_CS_PATH)
if (true)
{
execlp ("hello", "hello", NULL);
}
else
{
char *argv[2] = { "hello", NULL };
pid_t pid;
posix_spawnp (&pid, "hello", NULL, NULL, argv, environ);
}
}
>From 9b1b1673f7e60c28506efce1465602b1b06e2d5a Mon Sep 17 00:00:00 2001
From: Bruno Haible <[email protected]>
Date: Mon, 2 Nov 2026 12:23:19 +0100
Subject: [PATCH 1/2] findprog, findprog-lgpl: Use a default PATH like POSIX
specifies.
Reported by Collin Funk in
<https://lists.gnu.org/archive/html/coreutils/2026-11/msg00006.html>.
* m4/findprog.m4 (gl_FINDPROG): Check for confstr.
* lib/findprog.c (MAX_DEFAULT_PATH_SIZE): New macro.
(find_in_path): When confstr is available, use it to get the default PATH.
---
ChangeLog | 9 +++++++++
lib/findprog.c | 33 ++++++++++++++++++++++++++++++---
m4/findprog.m4 | 3 ++-
3 files changed, 41 insertions(+), 4 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 74d6d85e66..54b43c5ac5 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2026-11-02 Bruno Haible <[email protected]>
+
+ findprog, findprog-lgpl: Use a default PATH like POSIX specifies.
+ Reported by Collin Funk in
+ <https://lists.gnu.org/archive/html/coreutils/2026-11/msg00006.html>.
+ * m4/findprog.m4 (gl_FINDPROG): Check for confstr.
+ * lib/findprog.c (MAX_DEFAULT_PATH_SIZE): New macro.
+ (find_in_path): When confstr is available, use it to get the default PATH.
+
2026-11-01 Bruno Haible <[email protected]>
optional: Add tests.
diff --git a/lib/findprog.c b/lib/findprog.c
index 624e79318a..2d321dc0d9 100644
--- a/lib/findprog.c
+++ b/lib/findprog.c
@@ -37,6 +37,23 @@
#include "concat-filename.h"
+/* A buffer of size 256 should be sufficient, because the default PATH has
+ length < 100 on all systems seen so far:
+ - Linux, Hurd, macOS, Cygwin:
+ "/bin:/usr/bin"
+ - FreeBSD:
+ "/usr/bin:/bin:/usr/sbin:/sbin"
+ - NetBSD:
+ "/usr/bin:/bin:/usr/sbin:/sbin:/usr/pkg/bin:/usr/pkg/sbin:/usr/local/bin:/usr/local/sbin"
+ - OpenBSD:
+ "/usr/bin:/bin:/usr/sbin:/sbin:/usr/X11R6/bin:/usr/local/bin"
+ - Solaris 11.4:
+ "/usr/xpg6/bin:/usr/xpg4/bin:/usr/bin:/opt/developerstudio12.5/bin:/opt/solarisstudio12.4/bin"
+ - Haiku:
+ "/boot/system/non-packaged/bin:/bin:/boot/system/apps:/boot/system/preferences"
+ */
+#define MAX_DEFAULT_PATH_SIZE 256
+
const char *
find_in_path (const char *progname)
{
@@ -53,9 +70,19 @@ find_in_path (const char *progname)
return progname;
char *path = getenv ("PATH");
- if (path == NULL || *path == '\0')
- /* If PATH is not set, the default search path is implementation
- dependent. */
+ char default_path[MAX_DEFAULT_PATH_SIZE];
+ if (path == NULL)
+ {
+ /* If PATH is not set, the default search path is implementation
+ 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))
+ #endif
+ default_path[0] = '\0';
+ path = default_path;
+ }
+ if (*path == '\0')
return progname;
/* Make a copy, to prepare for destructive modifications. */
diff --git a/m4/findprog.m4 b/m4/findprog.m4
index bd80c219dd..af30280c25 100644
--- a/m4/findprog.m4
+++ b/m4/findprog.m4
@@ -1,5 +1,5 @@
# findprog.m4
-# serial 3
+# serial 4
dnl Copyright (C) 2003, 2009-2026 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
@@ -10,4 +10,5 @@ AC_DEFUN([gl_FINDPROG]
[
dnl Prerequisites of lib/findprog.c.
AC_REQUIRE([gl_FUNC_EACCESS])
+ AC_CHECK_FUNCS_ONCE([confstr])
])
--
2.53.0
>From 19e602707d71fcad44b2f282ab88cb5b0be3eee4 Mon Sep 17 00:00:00 2001
From: Bruno Haible <[email protected]>
Date: Mon, 2 Nov 2026 12:26:21 +0100
Subject: [PATCH 2/2] findprog-in: Use a default PATH like POSIX specifies.
Reported by Collin Funk in
<https://lists.gnu.org/archive/html/coreutils/2026-11/msg00006.html>.
Discovered by Anthropic's OSS Scanner, as bug ANT-2026-1R7RAVAG.
* m4/findprog-in.m4 (gl_FINDPROG_IN): Check for confstr.
* lib/findprog.h (find_in_given_path): Change specification of what a
null PATH means.
* lib/findprog-in.c (MAX_DEFAULT_PATH_SIZE): New macro.
(find_in_given_path): When confstr is available, use it to get the
default PATH.
---
ChangeLog | 13 +++++++++++++
lib/findprog-in.c | 31 ++++++++++++++++++++++++++++---
lib/findprog.h | 5 +++--
m4/findprog-in.m4 | 3 ++-
4 files changed, 46 insertions(+), 6 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 54b43c5ac5..2115938896 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2026-11-02 Bruno Haible <[email protected]>
+
+ findprog-in: Use a default PATH like POSIX specifies.
+ Reported by Collin Funk in
+ <https://lists.gnu.org/archive/html/coreutils/2026-11/msg00006.html>.
+ Discovered by Anthropic's OSS Scanner, as bug ANT-2026-1R7RAVAG.
+ * m4/findprog-in.m4 (gl_FINDPROG_IN): Check for confstr.
+ * lib/findprog.h (find_in_given_path): Change specification of what a
+ null PATH means.
+ * lib/findprog-in.c (MAX_DEFAULT_PATH_SIZE): New macro.
+ (find_in_given_path): When confstr is available, use it to get the
+ default PATH.
+
2026-11-02 Bruno Haible <[email protected]>
findprog, findprog-lgpl: Use a default PATH like POSIX specifies.
diff --git a/lib/findprog-in.c b/lib/findprog-in.c
index bbcae63286..d937f7c834 100644
--- a/lib/findprog-in.c
+++ b/lib/findprog-in.c
@@ -70,6 +70,23 @@ static const char * const suffixes[] =
#endif
};
+/* A buffer of size 256 should be sufficient, because the default PATH has
+ length < 100 on all systems seen so far:
+ - Linux, Hurd, macOS, Cygwin:
+ "/bin:/usr/bin"
+ - FreeBSD:
+ "/usr/bin:/bin:/usr/sbin:/sbin"
+ - NetBSD:
+ "/usr/bin:/bin:/usr/sbin:/sbin:/usr/pkg/bin:/usr/pkg/sbin:/usr/local/bin:/usr/local/sbin"
+ - OpenBSD:
+ "/usr/bin:/bin:/usr/sbin:/sbin:/usr/X11R6/bin:/usr/local/bin"
+ - Solaris 11.4:
+ "/usr/xpg6/bin:/usr/xpg4/bin:/usr/bin:/opt/developerstudio12.5/bin:/opt/solarisstudio12.4/bin"
+ - Haiku:
+ "/boot/system/non-packaged/bin:/bin:/boot/system/apps:/boot/system/preferences"
+ */
+#define MAX_DEFAULT_PATH_SIZE 256
+
const char *
find_in_given_path (const char *progname, const char *path,
const char *directory, bool optimize_for_exec)
@@ -199,10 +216,18 @@ find_in_given_path (const char *progname, const char *path,
}
}
+ char default_path[MAX_DEFAULT_PATH_SIZE];
if (path == NULL)
- /* If PATH is not set, the default search path is implementation dependent.
- In practice, it is treated like an empty PATH. */
- path = "";
+ {
+ /* If PATH is not set, the default search path is implementation
+ 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))
+ #endif
+ default_path[0] = '\0';
+ path = default_path;
+ }
{
/* Make a copy, to prepare for destructive modifications. */
diff --git a/lib/findprog.h b/lib/findprog.h
index 231b620b45..c83ace43ee 100644
--- a/lib/findprog.h
+++ b/lib/findprog.h
@@ -37,8 +37,9 @@ extern const char *find_in_path (const char *progname);
The PATH argument consists of a list of directories, separated by ':' or
(on native Windows) by ';'. An empty PATH element designates the current
- directory. A null PATH is equivalent to an empty PATH, that is, to the
- singleton list that contains only the current directory.
+ directory. A null PATH is equivalent to confstr (_CS_PATH) on POSIX systems,
+ or otherwise to an empty PATH, that is, to the singleton list that contains
+ only the current directory.
If DIRECTORY is not NULL, all relative filenames (i.e. PROGNAME when it
contains a slash, and the PATH elements) are considered relative to
diff --git a/m4/findprog-in.m4 b/m4/findprog-in.m4
index a78f9c6318..11997d085d 100644
--- a/m4/findprog-in.m4
+++ b/m4/findprog-in.m4
@@ -1,5 +1,5 @@
# findprog-in.m4
-# serial 1
+# serial 2
dnl Copyright (C) 2003, 2009-2026 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
@@ -10,4 +10,5 @@ AC_DEFUN([gl_FINDPROG_IN]
[
dnl Prerequisites of lib/findprog-in.c.
AC_REQUIRE([gl_FUNC_EACCESS])
+ AC_CHECK_FUNCS_ONCE([confstr])
])
--
2.53.0