]> git.ipfire.org Git - thirdparty/coreutils.git/commitdiff
du,ls: don’t modify getenv strings
authorPaul Eggert <eggert@cs.ucla.edu>
Sun, 23 Nov 2025 19:42:57 +0000 (11:42 -0800)
committerPaul Eggert <eggert@cs.ucla.edu>
Sun, 23 Nov 2025 20:00:09 +0000 (12:00 -0800)
Fix du and ls to conform to the POSIX getenv spec,
which says you can’t modify strings returned by getenv
unless you put the string there directly, or used putenv.
This portability bug was found by strict C23 checking
using qualifier-generic functions.
* bootstrap.conf (gnulib_modules): Add xmemdup0.  Sort.
* src/du.c (main):
* src/ls.c (decode_switches):
Don’t modify the string that getenv returns.
Instead, use xmemdup0 if needed, and include xmemdup0.h.

NEWS
bootstrap.conf
src/du.c
src/ls.c

diff --git a/NEWS b/NEWS
index acb3a4e18704a03c957967e96731164a6d6e796c..ed33d27aa84de97f0772275bf1c7c6bbdabb81ed 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -4,6 +4,10 @@ GNU coreutils NEWS                                    -*- outline -*-
 
 ** Bug fixes
 
+  du and ls no longer modify strings returned by getenv.
+  POSIX says this is not portable.
+  [bug introduced in fileutils-4.1.6]
+
   md5sum --text correctly translates CRLF line endings with the MSYS2 runtime.
   This also applies to the sha*sum and b2sum utilities.
   [This bug was present in "the beginning".]
@@ -16,6 +20,9 @@ GNU coreutils NEWS                                    -*- outline -*-
   indicate the line count acceleration being used.
   [bug introduced in coreutils-9.0]
 
+  Programs now port to C23 platforms that strictly check types when
+  qualifier-generic functions like strchr are used.
+
 ** New Features
 
   configure accepts a new --enable-single-binary=hardlinks mode to build the
index ec68ac8bfe5632cfb6177b9f39a7a6b15da67f7f..356aaabef8dc8a6c9cba040fda8ad3a81af0563e 100644 (file)
@@ -69,8 +69,8 @@ gnulib_modules="
   crc-x86_64
   crypto/md5
   crypto/sha1
-  crypto/sha3
   crypto/sha256
+  crypto/sha3
   crypto/sha512
   crypto/sm3
   cycle-check
@@ -215,14 +215,14 @@ gnulib_modules="
   pipe2
   posix-shell
   posix_spawn
-  posix_spawnattr_destroy
-  posix_spawnattr_init
-  posix_spawnattr_setflags
-  posix_spawnattr_setsigdefault
   posix_spawn_file_actions_addclose
   posix_spawn_file_actions_adddup2
   posix_spawn_file_actions_destroy
   posix_spawn_file_actions_init
+  posix_spawnattr_destroy
+  posix_spawnattr_init
+  posix_spawnattr_setflags
+  posix_spawnattr_setsigdefault
   posix_spawnp
   posixtm
   posixver
@@ -325,6 +325,7 @@ gnulib_modules="
   xgetgroups
   xgethostname
   xmemcoll
+  xmemdup0
   xnanosleep
   xprintf
   xprintf-posix
index c6d6d7b3348c99555b18545b5ac5a15052831c80..105acb2dfd07dc954d25d8a0549d95516fe284c9 100644 (file)
--- a/src/du.c
+++ b/src/du.c
@@ -40,6 +40,7 @@
 #include "stat-time.h"
 #include "stdio--.h"
 #include "xfts.h"
+#include "xmemdup0.h"
 #include "xstrtol.h"
 #include "xstrtol-error.h"
 
@@ -962,9 +963,9 @@ main (int argc, char **argv)
             {
               /* Ignore anything after a newline, for compatibility
                  with ls.  */
-              char *p = strchr (time_style, '\n');
+              char const *p = strchr (time_style, '\n');
               if (p)
-                *p = '\0';
+                time_style = xmemdup0 (time_style, p - time_style);
             }
           else
             {
index a81bab9c64ff74f9506710f7656f8bbfc4fa6677..6b5f2b053f4f8202246244423bdb06e8a2cd3723 100644 (file)
--- a/src/ls.c
+++ b/src/ls.c
 
 #include <fnmatch.h>
 
+/* Gnulib includes.  */
 #include "acl.h"
+#include "areadlink.h"
 #include "argmatch.h"
-#include "system.h"
 #include "assure.h"
+#include "c-ctype.h"
 #include "c-strcase.h"
+#include "canonicalize.h"
 #include "dev-ino.h"
+#include "filemode.h"
 #include "filenamecat.h"
+#include "filevercmp.h"
 #include "hard-locale.h"
 #include "hash.h"
 #include "human.h"
-#include "filemode.h"
-#include "filevercmp.h"
 #include "idcache.h"
-#include "ls.h"
 #include "mbswidth.h"
 #include "mpsort.h"
 #include "obstack.h"
 #include "stat-size.h"
 #include "stat-time.h"
 #include "strftime.h"
-#include "term-sig.h"
 #include "xdectoint.h"
-#include "xstrtol.h"
+#include "xgethostname.h"
+#include "xmemdup0.h"
 #include "xstrtol-error.h"
-#include "areadlink.h"
+#include "xstrtol.h"
+
+#include "system.h"
+
 #include "dircolors.h"
-#include "xgethostname.h"
-#include "c-ctype.h"
-#include "canonicalize.h"
+#include "ls.h"
 #include "statx.h"
+#include "term-sig.h"
 
 /* Include <sys/capability.h> last to avoid a clash of <sys/types.h>
    include guards with some premature versions of libcap.
@@ -1904,7 +1908,7 @@ stdout_isatty (void)
 static int
 decode_switches (int argc, char **argv)
 {
-  char const *time_style_option = nullptr;
+  char *time_style_option = nullptr;
 
   /* These variables are false or -1 unless a switch says otherwise.  */
   bool kibibytes_specified = false;
@@ -2151,7 +2155,7 @@ decode_switches (int argc, char **argv)
 
         case FULL_TIME_OPTION:
           format_opt = long_format;
-          time_style_option = "full-iso";
+          time_style_option = (char *) "full-iso";
           break;
 
         case COLOR_OPTION:
@@ -2377,35 +2381,39 @@ decode_switches (int argc, char **argv)
 
   if (format == long_format)
     {
-      char const *style = time_style_option;
-      static char const posix_prefix[] = "posix-";
-
+      char *envstyle = nullptr;
+      char *style = time_style_option;
       if (! style)
-        {
-          style = getenv ("TIME_STYLE");
-          if (! style)
-            style = "locale";
-        }
+        style = envstyle = getenv ("TIME_STYLE");
 
-      while (STREQ_LEN (style, posix_prefix, sizeof posix_prefix - 1))
+      if (! style)
+        style = (char *) "locale";
+      else
         {
-          if (! hard_locale (LC_TIME))
-            return optind;
-          style += sizeof posix_prefix - 1;
+          static char const posix_prefix[] = "posix-";
+          while (STREQ_LEN (style, posix_prefix, sizeof posix_prefix - 1))
+            {
+              if (! hard_locale (LC_TIME))
+                return optind;
+              style += sizeof posix_prefix - 1;
+            }
         }
 
       if (*style == '+')
         {
-          char const *p0 = style + 1;
+          char *p0 = style + 1;
           char *p0nl = strchr (p0, '\n');
           char const *p1 = p0;
           if (p0nl)
             {
-              if (strchr (p0nl + 1, '\n'))
+              p1 = p0nl + 1;
+              if (strchr (p1, '\n'))
                 error (LS_FAILURE, 0, _("invalid time style format %s"),
                        quote (p0));
-              *p0nl++ = '\0';
-              p1 = p0nl;
+              if (envstyle)
+                p0 = xmemdup0 (p0, p0nl - p0);
+              else
+                *p0nl = '\0';
             }
           long_time_format[0] = p0;
           long_time_format[1] = p1;