diff lib/putenv.c @ 17329:a72ac603a92f

putenv: fix heap corruption with mixed putenv/_putenv Problem reported by Michael Goffioul in <http://lists.gnu.org/archive/html/bug-gnulib/2013-02/msg00061.html>. * lib/putenv.c (putenv) [HAVE__PUTENV]: Rely on _putenv to allocate the new environment. * m4/putenv.m4 (gl_PREREQ_PUTENV): New macro. * modules/putenv (configure.ac): Use it.
author Paul Eggert <eggert@cs.ucla.edu>
date Thu, 14 Feb 2013 13:14:18 -0800
parents e542fd46ad6f
children cec099cbf54f
line wrap: on
line diff
--- a/lib/putenv.c	Thu Feb 14 09:43:22 2013 -0800
+++ b/lib/putenv.c	Thu Feb 14 13:14:18 2013 -0800
@@ -115,6 +115,37 @@
 
   if (*ep == NULL)
     {
+#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=x")
+             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 "=x");
+          if (!name_x)
+            return -1;
+          memcpy (name_x, string, name_end - string + 1);
+          name_x[name_end - string + 1] = 'x';
+          name_x[name_end - string + 2] = 0;
+          putenv_result = _putenv (name_x);
+          putenv_errno = errno;
+          for (ep = environ; *ep; ep++)
+            if (*ep == name_x)
+              {
+                *ep = string;
+                break;
+              }
+          free (name_x);
+          __set_errno (putenv_errno);
+          return putenv_result;
+        }
+#else
       static char **last_environ = NULL;
       char **new_environ = (char **) malloc ((size + 2) * sizeof (char *));
       if (new_environ == NULL)
@@ -126,6 +157,7 @@
       free (last_environ);
       last_environ = new_environ;
       environ = new_environ;
+#endif
     }
   else
     *ep = string;