From 89bd9d36859503e25b767f97395870190f272bc1 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Fri, 1 Mar 2013 07:16:43 -0800 Subject: [PATCH] Merge from gnulib. 2013-02-21 putenv: port better to native Windows 2013-02-18 extern-inline: avoid compilation error with HP-UX cc 2013-02-14 putenv: fix heap corruption with mixed putenv/_putenv --- ChangeLog | 7 ++++ lib/putenv.c | 94 ++++++++++++++++++++++++++++++++++++--------- m4/extern-inline.m4 | 5 ++- m4/gnulib-comp.m4 | 1 + m4/putenv.m4 | 6 +++ 5 files changed, 94 insertions(+), 19 deletions(-) diff --git a/ChangeLog b/ChangeLog index 7a2e7769ec..84d9987cce 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2013-03-01 Paul Eggert + + Merge from gnulib, incorporating: + 2013-02-21 putenv: port better to native Windows + 2013-02-18 extern-inline: avoid compilation error with HP-UX cc + 2013-02-14 putenv: fix heap corruption with mixed putenv/_putenv + 2013-02-28 Ken Brown * configure.ac (HAVE_DATA_START): Fix test. (Bug#13818) diff --git a/lib/putenv.c b/lib/putenv.c index 5f0fedaf9c..ed666afc3b 100644 --- a/lib/putenv.c +++ b/lib/putenv.c @@ -34,6 +34,11 @@ #include #include +#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ +# define WIN32_LEAN_AND_MEAN +# include +#endif + #if _LIBC # if HAVE_GNU_LD # define environ __environ @@ -67,6 +72,21 @@ _unsetenv (const char *name) len = strlen (name); +#if HAVE__PUTENV + { + int putenv_result, putenv_errno; + char *name_ = malloc (len + 2); + memcpy (name_, name, len); + name_[len] = '='; + name_[len + 1] = 0; + putenv_result = _putenv (name_); + putenv_errno = errno; + free (name_); + __set_errno (putenv_errno); + return putenv_result; + } +#else + LOCK; ep = environ; @@ -87,6 +107,7 @@ _unsetenv (const char *name) UNLOCK; return 0; +#endif } @@ -95,9 +116,8 @@ _unsetenv (const char *name) int putenv (char *string) { - const char *const name_end = strchr (string, '='); - register size_t size; - register char **ep; + const char *name_end = strchr (string, '='); + char **ep; if (name_end == NULL) { @@ -105,30 +125,68 @@ putenv (char *string) return _unsetenv (string); } - size = 0; - for (ep = environ; *ep != NULL; ++ep) - if (!strncmp (*ep, string, name_end - string) && - (*ep)[name_end - string] == '=') +#if HAVE__PUTENV + /* Rely on _putenv to allocate the new environment. If other + parts of the application use _putenv, the !HAVE__PUTENV code + would fight over who owns the environ vector, causing a crash. */ + if (name_end[1]) + return _putenv (string); + else + { + /* _putenv ("NAME=") unsets NAME, so invoke _putenv ("NAME= ") + to allocate the environ vector and then replace the new + entry with "NAME=". */ + int putenv_result, putenv_errno; + char *name_x = malloc (name_end - string + sizeof "= "); + if (!name_x) + return -1; + memcpy (name_x, string, name_end - string + 1); + name_x[name_end - string + 1] = ' '; + name_x[name_end - string + 2] = 0; + putenv_result = _putenv (name_x); + putenv_errno = errno; + for (ep = environ; *ep; ep++) + if (strcmp (*ep, name_x) == 0) + { + *ep = string; + break; + } +# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ + if (putenv_result == 0) + { + /* _putenv propagated "NAME= " into the subprocess environment; + fix that by calling SetEnvironmentVariable directly. */ + name_x[name_end - string] = 0; + putenv_result = SetEnvironmentVariable (name_x, "") ? 0 : -1; + putenv_errno = ENOMEM; /* ENOMEM is the only way to fail. */ + } +# endif + free (name_x); + __set_errno (putenv_errno); + return putenv_result; + } +#else + for (ep = environ; *ep; ep++) + if (strncmp (*ep, string, name_end - string) == 0 + && (*ep)[name_end - string] == '=') break; - else - ++size; - if (*ep == NULL) + if (*ep) + *ep = string; + else { static char **last_environ = NULL; - char **new_environ = (char **) malloc ((size + 2) * sizeof (char *)); - if (new_environ == NULL) + size_t size = ep - environ; + char **new_environ = malloc ((size + 2) * sizeof *new_environ); + if (! new_environ) return -1; - (void) memcpy ((void *) new_environ, (void *) environ, - size * sizeof (char *)); - new_environ[size] = (char *) string; - new_environ[size + 1] = NULL; + new_environ[0] = string; + memcpy (new_environ + 1, environ, (size + 1) * sizeof *new_environ); free (last_environ); last_environ = new_environ; environ = new_environ; } - else - *ep = string; +#endif return 0; } diff --git a/m4/extern-inline.m4 b/m4/extern-inline.m4 index 5880d4f454..0152f29326 100644 --- a/m4/extern-inline.m4 +++ b/m4/extern-inline.m4 @@ -18,13 +18,16 @@ AC_DEFUN([gl_EXTERN_INLINE], _GL_INLINE_HEADER_END contains useful stuff to put in the same include file, after uses of _GL_INLINE. + Suppress extern inline with HP-UX cc, as it appears to be broken; see + . + Suppress the use of extern inline on Apple's platforms, as Libc-825.25 (2012-09-19) is incompatible with it; see . Perhaps Apple will fix this some day. */ #if ((__GNUC__ \ ? defined __GNUC_STDC_INLINE__ && __GNUC_STDC_INLINE__ \ - : 199901L <= __STDC_VERSION__) \ + : 199901L <= __STDC_VERSION__ && !defined __HP_cc) \ && !defined __APPLE__) # define _GL_INLINE inline # define _GL_EXTERN_INLINE extern inline diff --git a/m4/gnulib-comp.m4 b/m4/gnulib-comp.m4 index a7987120c5..6c3012d827 100644 --- a/m4/gnulib-comp.m4 +++ b/m4/gnulib-comp.m4 @@ -271,6 +271,7 @@ AC_DEFUN([gl_INIT], gl_FUNC_PUTENV if test $REPLACE_PUTENV = 1; then AC_LIBOBJ([putenv]) + gl_PREREQ_PUTENV fi gl_STDLIB_MODULE_INDICATOR([putenv]) gl_FUNC_READLINK diff --git a/m4/putenv.m4 b/m4/putenv.m4 index 9de53527a7..03ed4f97db 100644 --- a/m4/putenv.m4 +++ b/m4/putenv.m4 @@ -48,3 +48,9 @@ AC_DEFUN([gl_FUNC_PUTENV], ;; esac ]) + +# Prerequisites of lib/putenv.c. +AC_DEFUN([gl_PREREQ_PUTENV], +[ + AC_CHECK_FUNCS([_putenv]) +]) -- 2.20.1