Patch to fix problem with refering environ

Michael Meissner meissner@redhat.com
Tue Oct 3 15:15:00 GMT 2000


The following patch goes through some hoops to make sure that environ
is only referenced via a statically intiialized pointer.  The case I
was working on showed up when the user defined their own environ and
compiled it with -G 0, while the library was compiled with a default
of -G 8, and the linker reported that environ was too far away from
the global pointer.  I have also worked on shared library systems that
had similar behavior for library data is used by the library but
defined by the user, so this fix fixes that rare case as well.

2000-10-03  Michael Meissner  <meissner@redhat.com>

	* libc/posix/execl.c (execl): Don't reference environ directly,
	reference it only via a static pointer to avoid problems with some
	shared library systems and with different uses of small data where
	the user specifies his own version of environ.
	* libc/posix/execv.c (execv): Ditto.
	* libc/stdlib/getenv_r.c (_findenv_r): Ditto.
	* libc/stdlib/setenv_r.c (_setenv_r,_unsetenv_r): Ditto.
	* libc/stdlib/system.c (system, !cygwin32 case): Ditto.

	* libc/stdlib/getenv.c (environ): Delete unused reference to
	environ.

	* libc/stdlib/getenv_r.c: Make initial comment friendlier to emacs
	colorization.
	* libc/stdlib/system.c: Ditto.

*** newlib/libc/posix/execl.c.~1~	Thu Feb 17 14:39:47 2000
--- newlib/libc/posix/execl.c	Tue Oct  3 18:05:01 2000
***************
*** 6,11 ****
--- 6,16 ----
  #include <_ansi.h>
  #include <unistd.h>
  
+ /* Only deal with a pointer to environ, to work around subtle bugs with shared
+    libraries and/or small data systems where the user declares his own
+    'environ'.  */
+ static char ***p_environ = &environ;
+ 
  #ifdef _HAVE_STDC
  
  #include <stdarg.h>
*************** execl (path, arg0, va_alist)
*** 38,42 ****
    while (argv[i++] != NULL);
    va_end (args);
  
!   return _execve (path, (char * _CONST  *) argv, environ);
  }
--- 43,47 ----
    while (argv[i++] != NULL);
    va_end (args);
  
!   return _execve (path, (char * _CONST  *) argv, *p_environ);
  }
*** newlib/libc/posix/execv.c.~1~	Thu Feb 17 14:39:47 2000
--- newlib/libc/posix/execv.c	Tue Oct  3 18:05:18 2000
***************
*** 6,15 ****
  #include <_ansi.h>
  #include <unistd.h>
  
  int
  _DEFUN (execv, (path, argv), 
  	const char *path _AND
  	char * const argv[])
  {
!   return _execve (path, (char * _CONST *) argv, environ);
  }
--- 6,20 ----
  #include <_ansi.h>
  #include <unistd.h>
  
+ /* Only deal with a pointer to environ, to work around subtle bugs with shared
+    libraries and/or small data systems where the user declares his own
+    'environ'.  */
+ static char ***p_environ = &environ;
+ 
  int
  _DEFUN (execv, (path, argv), 
  	const char *path _AND
  	char * const argv[])
  {
!   return _execve (path, (char * _CONST *) argv, *p_environ);
  }
*** newlib/libc/stdlib/getenv.c.~1~	Thu Feb 17 14:39:47 2000
--- newlib/libc/stdlib/getenv.c	Tue Oct  3 18:05:35 2000
*************** TRAD_SYNOPSIS
*** 18,24 ****
  
  DESCRIPTION
  <<getenv>> searches the list of environment variable names and values
! (using the global pointer `<<char **environ>>') for a variable whose
  name matches the string at <[name]>.  If a variable name matches,
  <<getenv>> returns a pointer to the associated value.
  
--- 18,24 ----
  
  DESCRIPTION
  <<getenv>> searches the list of environment variable names and values
! (using the global pointer ``<<char **environ>>'') for a variable whose
  name matches the string at <[name]>.  If a variable name matches,
  <<getenv>> returns a pointer to the associated value.
  
*************** variables vary from one system to anothe
*** 39,45 ****
  */
  
  /*
!  * Copyright (c) 1987 Regents of the University of California.
   * All rights reserved.
   *
   * Redistribution and use in source and binary forms are permitted
--- 39,45 ----
  */
  
  /*
!  * Copyright (c) 1987, 2000 Regents of the University of California.
   * All rights reserved.
   *
   * Redistribution and use in source and binary forms are permitted
*************** variables vary from one system to anothe
*** 62,69 ****
  #include <stdlib.h>
  #include <stddef.h>
  #include <string.h>
- 
- extern char **environ;
  
  /*
   * _findenv --
--- 62,67 ----
*** newlib/libc/stdlib/getenv_r.c.~1~	Thu Feb 17 14:39:47 2000
--- newlib/libc/stdlib/getenv_r.c	Tue Oct  3 18:05:54 2000
*************** TRAD_SYNOPSIS
*** 19,25 ****
  
  DESCRIPTION
  <<_getenv_r>> searches the list of environment variable names and values
! (using the global pointer `<<char **environ>>') for a variable whose
  name matches the string at <[name]>.  If a variable name matches,
  <<_getenv_r>> returns a pointer to the associated value.
  
--- 19,25 ----
  
  DESCRIPTION
  <<_getenv_r>> searches the list of environment variable names and values
! (using the global pointer ``<<char **environ>>'') for a variable whose
  name matches the string at <[name]>.  If a variable name matches,
  <<_getenv_r>> returns a pointer to the associated value.
  
*************** variables vary from one system to anothe
*** 65,70 ****
--- 65,75 ----
  
  extern char **environ;
  
+ /* Only deal with a pointer to environ, to work around subtle bugs with shared
+    libraries and/or small data systems where the user declares his own
+    'environ'.  */
+ static char ***p_environ = &environ;
+ 
  /*
   * _findenv --
   *	Returns pointer to value associated with name, if any, else NULL.
*************** _DEFUN (_findenv_r, (reent_ptr, name, of
*** 89,95 ****
  
    /* In some embedded systems, this does not get set.  This protects
       newlib from dereferencing a bad pointer.  */
!   if (!environ)
      return NULL;
  
    c = name;
--- 94,100 ----
  
    /* In some embedded systems, this does not get set.  This protects
       newlib from dereferencing a bad pointer.  */
!   if (!*p_environ)
      return NULL;
  
    c = name;
*************** _DEFUN (_findenv_r, (reent_ptr, name, of
*** 100,110 ****
        len++;
      }
  
!   for (p = environ; *p; ++p)
      if (!strncmp (*p, name, len))
        if (*(c = *p + len) == '=')
  	{
! 	  *offset = p - environ;
            ENV_UNLOCK;
  	  return (char *) (++c);
  	}
--- 105,115 ----
        len++;
      }
  
!   for (p = *p_environ; *p; ++p)
      if (!strncmp (*p, name, len))
        if (*(c = *p + len) == '=')
  	{
! 	  *offset = p - *p_environ;
            ENV_UNLOCK;
  	  return (char *) (++c);
  	}
*** newlib/libc/stdlib/setenv_r.c.~1~	Mon Apr 17 13:10:17 2000
--- newlib/libc/stdlib/setenv_r.c	Tue Oct  3 18:06:15 2000
***************
*** 29,34 ****
--- 29,41 ----
  #include <string.h>
  #include "envlock.h"
  
+ extern char **environ;
+ 
+ /* Only deal with a pointer to environ, to work around subtle bugs with shared
+    libraries and/or small data systems where the user declares his own
+    'environ'.  */
+ static char ***p_environ = &environ;
+ 
  /* _findenv_r is defined in getenv_r.c.  */
  extern char *_findenv_r _PARAMS ((struct _reent *, const char *, int *));
  
*************** _DEFUN (_setenv_r, (reent_ptr, name, val
*** 45,51 ****
  	_CONST char *value _AND
  	int rewrite)
  {
-   extern char **environ;
    static int alloced;		/* if allocated space before */
    register char *C;
    int l_value, offset;
--- 52,57 ----
*************** _DEFUN (_setenv_r, (reent_ptr, name, val
*** 74,85 ****
        register int cnt;
        register char **P;
  
!       for (P = environ, cnt = 0; *P; ++P, ++cnt);
        if (alloced)
  	{			/* just increase size */
! 	  environ = (char **) _realloc_r (reent_ptr, (char *) environ,
! 				       (size_t) (sizeof (char *) * (cnt + 2)));
! 	  if (!environ)
              {
                ENV_UNLOCK;
  	      return -1;
--- 80,91 ----
        register int cnt;
        register char **P;
  
!       for (P = *p_environ, cnt = 0; *P; ++P, ++cnt);
        if (alloced)
  	{			/* just increase size */
! 	  *p_environ = (char **) _realloc_r (reent_ptr, (char *) environ,
! 					     (size_t) (sizeof (char *) * (cnt + 2)));
! 	  if (!*p_environ)
              {
                ENV_UNLOCK;
  	      return -1;
*************** _DEFUN (_setenv_r, (reent_ptr, name, val
*** 94,113 ****
                ENV_UNLOCK;
  	      return (-1);
              }
! 	  bcopy ((char *) environ, (char *) P, cnt * sizeof (char *));
! 	  environ = P;
  	}
!       environ[cnt + 1] = NULL;
        offset = cnt;
      }
    for (C = (char *) name; *C && *C != '='; ++C);	/* no `=' in name */
!   if (!(environ[offset] =	/* name + `=' + value */
  	_malloc_r (reent_ptr, (size_t) ((int) (C - name) + l_value + 2))))
      {
        ENV_UNLOCK;
        return -1;
      }
!   for (C = environ[offset]; (*C = *name++) && *C != '='; ++C);
    for (*C++ = '='; (*C++ = *value++) != 0;);
  
    ENV_UNLOCK;
--- 100,119 ----
                ENV_UNLOCK;
  	      return (-1);
              }
! 	  bcopy ((char *) *p_environ, (char *) P, cnt * sizeof (char *));
! 	  *p_environ = P;
  	}
!       (*p_environ)[cnt + 1] = NULL;
        offset = cnt;
      }
    for (C = (char *) name; *C && *C != '='; ++C);	/* no `=' in name */
!   if (!((*p_environ)[offset] =	/* name + `=' + value */
  	_malloc_r (reent_ptr, (size_t) ((int) (C - name) + l_value + 2))))
      {
        ENV_UNLOCK;
        return -1;
      }
!   for (C = (*p_environ)[offset]; (*C = *name++) && *C != '='; ++C);
    for (*C++ = '='; (*C++ = *value++) != 0;);
  
    ENV_UNLOCK;
*************** _DEFUN (_unsetenv_r, (reent_ptr, name),
*** 124,137 ****
          struct _reent *reent_ptr _AND
          _CONST char *name)
  {
-   extern char **environ;
    register char **P;
    int offset;
  
    ENV_LOCK;
  
    while (_findenv_r (reent_ptr, name, &offset))	/* if set multiple times */
!     for (P = &environ[offset];; ++P)
        if (!(*P = *(P + 1)))
  	break;
  
--- 130,142 ----
          struct _reent *reent_ptr _AND
          _CONST char *name)
  {
    register char **P;
    int offset;
  
    ENV_LOCK;
  
    while (_findenv_r (reent_ptr, name, &offset))	/* if set multiple times */
!     for (P = &(*p_environ)[offset];; ++P)
        if (!(*P = *(P + 1)))
  	break;
  
*** newlib/libc/stdlib/system.c.~1~	Tue Oct  3 18:03:04 2000
--- newlib/libc/stdlib/system.c	Tue Oct  3 18:06:38 2000
*************** DESCRIPTION
*** 27,33 ****
  Use <<system>> to pass a command string <<*<[s]>>> to <</bin/sh>> on
  your system, and wait for it to finish executing.
  
! Use `<<system(NULL)>>' to test whether your system has <</bin/sh>>
  available.
  
  The alternate function <<_system_r>> is a reentrant version.  The
--- 27,33 ----
  Use <<system>> to pass a command string <<*<[s]>>> to <</bin/sh>> on
  your system, and wait for it to finish executing.
  
! Use ``<<system(NULL)>>'' to test whether your system has <</bin/sh>>
  available.
  
  The alternate function <<_system_r>> is a reentrant version.  The
*************** system (s)
*** 107,112 ****
--- 107,119 ----
  #endif
  
  #if defined (unix) && !defined (__CYGWIN__)
+ extern char **environ;
+ 
+ /* Only deal with a pointer to environ, to work around subtle bugs with shared
+    libraries and/or small data systems where the user declares his own
+    'environ'.  */
+ static char ***p_environ = &environ;
+ 
  static int
  do_system (ptr, s)
       struct _reent *ptr;
*************** do_system (ptr, s)
*** 114,120 ****
  {
    char *argv[4];
    int pid, status;
-   extern char **environ;
  
    argv[0] = "sh";
    argv[1] = "-c";
--- 121,126 ----
*************** do_system (ptr, s)
*** 123,129 ****
  
    if ((pid = _fork_r (ptr)) == 0)
      {
!       _execve ("/bin/sh", argv, environ);
        exit (100);
      }
    else if (pid == -1)
--- 129,135 ----
  
    if ((pid = _fork_r (ptr)) == 0)
      {
!       _execve ("/bin/sh", argv, *p_environ);
        exit (100);
      }
    else if (pid == -1)

-- 
Michael Meissner, Red Hat, Inc.
PMB 198, 174 Littleton Road #3, Westford, Massachusetts 01886, USA
Work:	  meissner@redhat.com		phone: +1 978-486-9304
Non-work: meissner@spectacle-pond.org	fax:   +1 978-692-4482


More information about the Newlib mailing list