From 702533233dfc861107c4bfbcfd8af76e246f2820 Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Thu, 6 Jun 2024 01:21:28 +0200 Subject: [PATCH] unsetenv: On native Windows, don't modify _environ directly. * m4/setenv.m4 (gl_PREREQ_UNSETENV): Check for _putenv. * lib/unsetenv.c (unsetenv): Add native Windows handling, from lib/putenv.c. * modules/unsetenv (Depends-on): Add free-posix, malloc-posix. * m4/putenv.m4 (gl_FUNC_PUTENV): Use AC_CHECK_DECLS_ONCE. * lib/putenv.c (_unsetenv): Moved to lib/unsetenv.c. (putenv): Invoke unsetenv instead of _unsetenv. * modules/putenv (Depends-on): Add unsetenv. --- ChangeLog | 12 +++++++++ lib/putenv.c | 67 +----------------------------------------------- lib/unsetenv.c | 34 +++++++++++++++++++++--- m4/putenv.m4 | 6 ++--- m4/setenv.m4 | 5 ++-- modules/putenv | 1 + modules/unsetenv | 2 ++ 7 files changed, 53 insertions(+), 74 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8005d2856b..1e7e4ecfc1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2024-06-05 Bruno Haible + + unsetenv: On native Windows, don't modify _environ directly. + * m4/setenv.m4 (gl_PREREQ_UNSETENV): Check for _putenv. + * lib/unsetenv.c (unsetenv): Add native Windows handling, from + lib/putenv.c. + * modules/unsetenv (Depends-on): Add free-posix, malloc-posix. + * m4/putenv.m4 (gl_FUNC_PUTENV): Use AC_CHECK_DECLS_ONCE. + * lib/putenv.c (_unsetenv): Moved to lib/unsetenv.c. + (putenv): Invoke unsetenv instead of _unsetenv. + * modules/putenv (Depends-on): Add unsetenv. + 2024-06-05 Bruno Haible putenv: Don't crash upon out-of-memory. diff --git a/lib/putenv.c b/lib/putenv.c index 1d70717e0f..d3084c9e60 100644 --- a/lib/putenv.c +++ b/lib/putenv.c @@ -64,71 +64,6 @@ __libc_lock_define_initialized (static, envlock) # define SetEnvironmentVariable SetEnvironmentVariableA #endif -static int -_unsetenv (const char *name) -{ - size_t len; - - if (name == NULL || *name == '\0' || strchr (name, '=') != NULL) - { - __set_errno (EINVAL); - return -1; - } - - len = strlen (name); - -#if HAVE_DECL__PUTENV /* native Windows */ - /* The Microsoft documentation - - says: - "Don't change an environment entry directly: instead, - use _putenv or _wputenv to change it." - Note: Microsoft's _putenv updates not only the contents of _environ but - also the contents of _wenviron, so that both are in kept in sync. - - The way to remove an environment variable is to pass to _putenv a string - of the form "NAME=". (NB: This is a different convention than with glibc - putenv, which expects a string of the form "NAME"!) */ - { - int putenv_result; - char *name_ = malloc (len + 2); - if (name_ == NULL) - return -1; - memcpy (name_, name, len); - name_[len] = '='; - name_[len + 1] = 0; - putenv_result = _putenv (name_); - /* In this particular case it is OK to free() the argument passed to - _putenv. */ - free (name_); - return putenv_result; - } -#else - - LOCK; - - char **ep = environ; - while (*ep != NULL) - if (!strncmp (*ep, name, len) && (*ep)[len] == '=') - { - /* Found it. Remove this pointer by moving later ones back. */ - char **dp = ep; - - do - dp[0] = dp[1]; - while (*dp++); - /* Continue the loop in case NAME appears again. */ - } - else - ++ep; - - UNLOCK; - - return 0; -#endif -} - - /* Put STRING, which is of the form "NAME=VALUE", in the environment. If STRING contains no '=', then remove STRING from the environment. */ int @@ -140,7 +75,7 @@ putenv (char *string) if (name_end == NULL) { /* Remove the variable from the environment. */ - return _unsetenv (string); + return unsetenv (string); } #if HAVE_DECL__PUTENV /* native Windows */ diff --git a/lib/unsetenv.c b/lib/unsetenv.c index e5489490f7..5e989968c1 100644 --- a/lib/unsetenv.c +++ b/lib/unsetenv.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1992, 1995-2002, 2005-2023 Free Software Foundation, Inc. +/* Copyright (C) 1992, 1995-2002, 2005-2024 Free Software Foundation, Inc. This file is part of the GNU C Library. This file is free software: you can redistribute it and/or modify @@ -57,7 +57,6 @@ int unsetenv (const char *name) { size_t len; - char **ep; if (name == NULL || *name == '\0' || strchr (name, '=') != NULL) { @@ -67,9 +66,37 @@ unsetenv (const char *name) len = strlen (name); +#if HAVE_DECL__PUTENV /* native Windows */ + /* The Microsoft documentation + + says: + "Don't change an environment entry directly: instead, + use _putenv or _wputenv to change it." + Note: Microsoft's _putenv updates not only the contents of _environ but + also the contents of _wenviron, so that both are in kept in sync. + + The way to remove an environment variable is to pass to _putenv a string + of the form "NAME=". (NB: This is a different convention than with glibc + putenv, which expects a string of the form "NAME"!) */ + { + int putenv_result; + char *name_ = malloc (len + 2); + if (name_ == NULL) + return -1; + memcpy (name_, name, len); + name_[len] = '='; + name_[len + 1] = 0; + putenv_result = _putenv (name_); + /* In this particular case it is OK to free() the argument passed to + _putenv. */ + free (name_); + return putenv_result; + } +#else + LOCK; - ep = __environ; + char **ep = __environ; while (*ep != NULL) if (!strncmp (*ep, name, len) && (*ep)[len] == '=') { @@ -87,6 +114,7 @@ unsetenv (const char *name) UNLOCK; return 0; +#endif } #ifdef _LIBC diff --git a/m4/putenv.m4 b/m4/putenv.m4 index d37a60213f..388d00ea8c 100644 --- a/m4/putenv.m4 +++ b/m4/putenv.m4 @@ -1,5 +1,5 @@ -# putenv.m4 serial 26 -dnl Copyright (C) 2002-2023 Free Software Foundation, Inc. +# putenv.m4 serial 26.1 +dnl Copyright (C) 2002-2024 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. @@ -60,5 +60,5 @@ AC_DEFUN([gl_FUNC_PUTENV], # Prerequisites of lib/putenv.c. AC_DEFUN([gl_PREREQ_PUTENV], [ - AC_CHECK_DECLS([_putenv]) + AC_CHECK_DECLS_ONCE([_putenv]) ]) diff --git a/m4/setenv.m4 b/m4/setenv.m4 index a30523d6a3..c31a5837d6 100644 --- a/m4/setenv.m4 +++ b/m4/setenv.m4 @@ -1,5 +1,5 @@ -# setenv.m4 serial 33 -dnl Copyright (C) 2001-2004, 2006-2023 Free Software Foundation, Inc. +# setenv.m4 serial 34 +dnl Copyright (C) 2001-2004, 2006-2024 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. @@ -162,4 +162,5 @@ AC_DEFUN([gl_PREREQ_UNSETENV], [ AC_REQUIRE([gl_ENVIRON]) AC_CHECK_HEADERS_ONCE([unistd.h]) + AC_CHECK_DECLS_ONCE([_putenv]) ]) diff --git a/modules/putenv b/modules/putenv index a5a7c8d795..d644d3ff26 100644 --- a/modules/putenv +++ b/modules/putenv @@ -10,6 +10,7 @@ stdlib environ [test $REPLACE_PUTENV = 1] free-posix [test $REPLACE_PUTENV = 1] malloc-posix [test $REPLACE_PUTENV = 1] +unsetenv [test $REPLACE_PUTENV = 1] configure.ac: gl_FUNC_PUTENV diff --git a/modules/unsetenv b/modules/unsetenv index 0e603a5b76..302d970814 100644 --- a/modules/unsetenv +++ b/modules/unsetenv @@ -9,6 +9,8 @@ Depends-on: stdlib unistd [test $HAVE_UNSETENV = 0 || test $REPLACE_UNSETENV = 1] environ [test $HAVE_UNSETENV = 0 || test $REPLACE_UNSETENV = 1] +free-posix [test $HAVE_UNSETENV = 0 || test $REPLACE_UNSETENV = 1] +malloc-posix [test $HAVE_UNSETENV = 0 || test $REPLACE_UNSETENV = 1] configure.ac: gl_FUNC_UNSETENV -- 2.39.5