du,ls: don’t modify getenv strings

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.
This commit is contained in:
Paul Eggert 2025-11-23 11:42:57 -08:00
parent eade022f24
commit 2199c9003e
4 changed files with 53 additions and 36 deletions

7
NEWS
View File

@ -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

View 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

View File

@ -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
{

View File

@ -70,20 +70,22 @@
#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"
@ -91,16 +93,18 @@
#include "stat-size.h"
#include "stat-time.h"
#include "strftime.h"
#include "term-sig.h"
#include "xdectoint.h"
#include "xstrtol.h"
#include "xstrtol-error.h"
#include "areadlink.h"
#include "dircolors.h"
#include "xgethostname.h"
#include "c-ctype.h"
#include "canonicalize.h"
#include "xmemdup0.h"
#include "xstrtol-error.h"
#include "xstrtol.h"
#include "system.h"
#include "dircolors.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 = envstyle = getenv ("TIME_STYLE");
if (! style)
style = (char *) "locale";
else
{
style = getenv ("TIME_STYLE");
if (! style)
style = "locale";
}
while (STREQ_LEN (style, posix_prefix, sizeof posix_prefix - 1))
{
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;