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

Reply via email to