mirror of
https://git.savannah.gnu.org/git/gnulib.git
synced 2025-08-10 04:43:00 +03:00
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-gnu (Depends-on): Add unsetenv.
This commit is contained in:
12
ChangeLog
12
ChangeLog
@@ -1,3 +1,15 @@
|
|||||||
|
2024-06-05 Bruno Haible <bruno@clisp.org>
|
||||||
|
|
||||||
|
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-gnu (Depends-on): Add unsetenv.
|
||||||
|
|
||||||
2024-06-05 Bruno Haible <bruno@clisp.org>
|
2024-06-05 Bruno Haible <bruno@clisp.org>
|
||||||
|
|
||||||
putenv: Don't crash upon out-of-memory.
|
putenv: Don't crash upon out-of-memory.
|
||||||
|
67
lib/putenv.c
67
lib/putenv.c
@@ -64,71 +64,6 @@ __libc_lock_define_initialized (static, envlock)
|
|||||||
# define SetEnvironmentVariable SetEnvironmentVariableA
|
# define SetEnvironmentVariable SetEnvironmentVariableA
|
||||||
#endif
|
#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
|
|
||||||
<https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/putenv-wputenv>
|
|
||||||
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.
|
/* Put STRING, which is of the form "NAME=VALUE", in the environment.
|
||||||
If STRING contains no '=', then remove STRING from the environment. */
|
If STRING contains no '=', then remove STRING from the environment. */
|
||||||
int
|
int
|
||||||
@@ -140,7 +75,7 @@ putenv (char *string)
|
|||||||
if (name_end == NULL)
|
if (name_end == NULL)
|
||||||
{
|
{
|
||||||
/* Remove the variable from the environment. */
|
/* Remove the variable from the environment. */
|
||||||
return _unsetenv (string);
|
return unsetenv (string);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if HAVE_DECL__PUTENV /* native Windows */
|
#if HAVE_DECL__PUTENV /* native Windows */
|
||||||
|
@@ -57,7 +57,6 @@ int
|
|||||||
unsetenv (const char *name)
|
unsetenv (const char *name)
|
||||||
{
|
{
|
||||||
size_t len;
|
size_t len;
|
||||||
char **ep;
|
|
||||||
|
|
||||||
if (name == NULL || *name == '\0' || strchr (name, '=') != NULL)
|
if (name == NULL || *name == '\0' || strchr (name, '=') != NULL)
|
||||||
{
|
{
|
||||||
@@ -67,9 +66,37 @@ unsetenv (const char *name)
|
|||||||
|
|
||||||
len = strlen (name);
|
len = strlen (name);
|
||||||
|
|
||||||
|
#if HAVE_DECL__PUTENV /* native Windows */
|
||||||
|
/* The Microsoft documentation
|
||||||
|
<https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/putenv-wputenv>
|
||||||
|
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;
|
LOCK;
|
||||||
|
|
||||||
ep = __environ;
|
char **ep = __environ;
|
||||||
while (*ep != NULL)
|
while (*ep != NULL)
|
||||||
if (!strncmp (*ep, name, len) && (*ep)[len] == '=')
|
if (!strncmp (*ep, name, len) && (*ep)[len] == '=')
|
||||||
{
|
{
|
||||||
@@ -87,6 +114,7 @@ unsetenv (const char *name)
|
|||||||
UNLOCK;
|
UNLOCK;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _LIBC
|
#ifdef _LIBC
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
# putenv.m4
|
# putenv.m4
|
||||||
# serial 27
|
# serial 28
|
||||||
dnl Copyright (C) 2002-2024 Free Software Foundation, Inc.
|
dnl Copyright (C) 2002-2024 Free Software Foundation, Inc.
|
||||||
dnl This file is free software; the Free Software Foundation
|
dnl This file is free software; the Free Software Foundation
|
||||||
dnl gives unlimited permission to copy and/or distribute it,
|
dnl gives unlimited permission to copy and/or distribute it,
|
||||||
@@ -61,5 +61,5 @@ AC_DEFUN([gl_FUNC_PUTENV],
|
|||||||
# Prerequisites of lib/putenv.c.
|
# Prerequisites of lib/putenv.c.
|
||||||
AC_DEFUN([gl_PREREQ_PUTENV],
|
AC_DEFUN([gl_PREREQ_PUTENV],
|
||||||
[
|
[
|
||||||
AC_CHECK_DECLS([_putenv])
|
AC_CHECK_DECLS_ONCE([_putenv])
|
||||||
])
|
])
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
# setenv.m4
|
# setenv.m4
|
||||||
# serial 33
|
# serial 34
|
||||||
dnl Copyright (C) 2001-2004, 2006-2024 Free Software Foundation, Inc.
|
dnl Copyright (C) 2001-2004, 2006-2024 Free Software Foundation, Inc.
|
||||||
dnl This file is free software; the Free Software Foundation
|
dnl This file is free software; the Free Software Foundation
|
||||||
dnl gives unlimited permission to copy and/or distribute it,
|
dnl gives unlimited permission to copy and/or distribute it,
|
||||||
@@ -163,4 +163,5 @@ AC_DEFUN([gl_PREREQ_UNSETENV],
|
|||||||
[
|
[
|
||||||
AC_REQUIRE([gl_ENVIRON])
|
AC_REQUIRE([gl_ENVIRON])
|
||||||
AC_CHECK_HEADERS_ONCE([unistd.h])
|
AC_CHECK_HEADERS_ONCE([unistd.h])
|
||||||
|
AC_CHECK_DECLS_ONCE([_putenv])
|
||||||
])
|
])
|
||||||
|
@@ -10,6 +10,7 @@ stdlib
|
|||||||
environ [test $REPLACE_PUTENV = 1]
|
environ [test $REPLACE_PUTENV = 1]
|
||||||
free-posix [test $REPLACE_PUTENV = 1]
|
free-posix [test $REPLACE_PUTENV = 1]
|
||||||
malloc-posix [test $REPLACE_PUTENV = 1]
|
malloc-posix [test $REPLACE_PUTENV = 1]
|
||||||
|
unsetenv [test $REPLACE_PUTENV = 1]
|
||||||
|
|
||||||
configure.ac:
|
configure.ac:
|
||||||
gl_FUNC_PUTENV
|
gl_FUNC_PUTENV
|
||||||
|
@@ -9,6 +9,8 @@ Depends-on:
|
|||||||
stdlib
|
stdlib
|
||||||
unistd [test $HAVE_UNSETENV = 0 || test $REPLACE_UNSETENV = 1]
|
unistd [test $HAVE_UNSETENV = 0 || test $REPLACE_UNSETENV = 1]
|
||||||
environ [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:
|
configure.ac:
|
||||||
gl_FUNC_UNSETENV
|
gl_FUNC_UNSETENV
|
||||||
|
Reference in New Issue
Block a user