Keep __p__environ sowehow actual

Uwe Bonnes bon at elektron.ikp.physik.tu-darmstadt.de
Mon Jul 8 17:21:42 CDT 2002


Hallo,

until now, on msvcrt load we took a snapshot of the poiters to Environment
variables given back by GetEnvironmentStrings and kept these pointer
static. As the target to these pointers may change e.g. after
SetEnvironmentVariable(), this resulted in strange things.

Changelog:
	dlls/msvcrt/data.c, environment.s: msvcrt_init_args, _putenv
	Take a snapshot of the environment strings when building the
	__p__environ array and update the array on calls to _putenv
-- 
Uwe Bonnes                bon at elektron.ikp.physik.tu-darmstadt.de

Free Software: If you contribute nothing, expect nothing
--
Index: wine/dlls/msvcrt/data.c
===================================================================
RCS file: /home/wine/wine/dlls/msvcrt/data.c,v
retrieving revision 1.16
diff -u -r1.16 data.c
--- wine/dlls/msvcrt/data.c	16 May 2002 23:16:01 -0000	1.16
+++ wine/dlls/msvcrt/data.c	8 Jul 2002 22:10:24 -0000
@@ -55,15 +55,103 @@
 WCHAR **MSVCRT___wargv;
 char *MSVCRT__acmdln;
 WCHAR *MSVCRT__wcmdln;
-char **MSVCRT__environ;
-WCHAR **MSVCRT__wenviron;
-char **MSVCRT___initenv;
-WCHAR **MSVCRT___winitenv;
+char **MSVCRT__environ = 0;
+WCHAR **MSVCRT__wenviron = 0;
+char **MSVCRT___initenv = 0;
+WCHAR **MSVCRT___winitenv = 0;
 int MSVCRT_timezone;
 int MSVCRT_app_type;
 
-static char* environ_strings;
-static WCHAR* wenviron_strings;
+/* Get a snapshot of the current environment 
+ * and construct the __p__environ array 
+ *
+ * The pointer returned from GetEnvironmentStrings may get invalid when
+ * some other module cause a reallocation of the env-variable block
+ * 
+ * blk is an array of pointers to environment strings, ending with a NULL
+ * and after that the actual copy of the environment strings, ending in a \0
+ */
+char ** SnapshotOfEnvironmentA(char **blk)
+{
+  char* environ_strings = GetEnvironmentStringsA();
+  int count = 1, len = 1, i = 0; /* keep space for the trailing NULLS */
+  char *ptr;
+
+  environ_strings = HeapAlloc(GetProcessHeap(), 0,100);
+  HeapFree(GetProcessHeap(), 0, environ_strings);
+  environ_strings = GetEnvironmentStringsA();
+  for (ptr = environ_strings; *ptr; ptr += strlen(ptr) + 1)
+  {
+    count++;
+    len += strlen(ptr) + 1;
+  }
+  if (blk)
+    {
+      if (HeapSize( GetProcessHeap(), 0, blk) < count* sizeof(char*)
+	  + len * sizeof(char))
+	blk = HeapReAlloc( GetProcessHeap(), 0, blk, count* sizeof(char*) +
+		     len * sizeof(char));
+    }
+  else
+    blk = HeapAlloc(GetProcessHeap(), 0, count* sizeof(char*) 
+		    + len * sizeof(char));
+  if (blk)
+    {
+      if (count)
+	{
+	  memcpy(&blk[count],environ_strings,len  * sizeof(char));
+	  for (ptr = (char*) &blk[count]; *ptr; ptr += strlen(ptr) + 1)
+	    {
+	      blk[i++] = ptr;
+	    }
+	}
+      blk[i] = NULL;
+	    blk[count-2], blk[count-2], i, count);
+    }
+  FreeEnvironmentStringsA(environ_strings);
+  environ_strings = HeapAlloc(GetProcessHeap(), 0,100);
+  HeapFree(GetProcessHeap(), 0, environ_strings);
+  return blk;
+}  
+
+WCHAR ** SnapshotOfEnvironmentW(WCHAR **wblk)
+{
+  WCHAR* wenviron_strings = GetEnvironmentStringsW();
+  int count = 1, len = 1, i = 0; /* keep space for the trailing NULLS */
+  WCHAR *wptr;
+
+  for (wptr = wenviron_strings; *wptr; wptr += lstrlenW(wptr) + 1)
+  {
+    count++;
+    len += lstrlenW(wptr) + 1;
+  }
+  if (wblk)
+    {
+      if (HeapSize( GetProcessHeap(), 0, wblk) < count* sizeof(WCHAR*) 
+	  + len * sizeof(WCHAR))
+	wblk = HeapReAlloc( GetProcessHeap(), 0, wblk, count* sizeof(WCHAR*)
+		     + len * sizeof(WCHAR));
+    }
+  else
+    wblk = HeapAlloc(GetProcessHeap(), 0, count* sizeof(WCHAR*) 
+		     + len * sizeof(WCHAR));
+  if (wblk)
+    {
+      if (count)
+	{
+	  memcpy(&wblk[count],wenviron_strings,len * sizeof(WCHAR));
+	  for (wptr = (WCHAR*)&wblk[count]; *wptr; wptr += lstrlenW(wptr) + 1)
+	    {
+	      wblk[i++] = wptr;
+	    }
+	}
+      wblk[i] = NULL;
+    }
+  FreeEnvironmentStringsW(wenviron_strings);
+  wenviron_strings = HeapAlloc(GetProcessHeap(), 0,100);
+  HeapFree(GetProcessHeap(), 0, wenviron_strings);
+  return wblk;
+}  
 
 typedef void (*_INITTERMFUN)(void);
 
@@ -125,12 +213,22 @@
 /*********************************************************************
  *		__p__environ (MSVCRT.@)
  */
-char*** __p__environ(void) { return &MSVCRT__environ; }
+char*** __p__environ(void) 
+{
+  if (!MSVCRT__environ)
+    MSVCRT__environ = SnapshotOfEnvironmentA(NULL);
+  return &MSVCRT__environ; 
+}
 
 /*********************************************************************
  *		__p__wenviron (MSVCRT.@)
  */
-WCHAR*** __p__wenviron(void) { return &MSVCRT__wenviron; }
+WCHAR*** __p__wenviron(void) 
+{ 
+  if (!MSVCRT__wenviron)
+    MSVCRT__wenviron = SnapshotOfEnvironmentW(NULL);
+  return &MSVCRT__wenviron;
+}
 
 /*********************************************************************
  *		__p___initenv (MSVCRT.@)
@@ -157,7 +255,7 @@
    MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,str,len*sizeof(char),wstr,len* sizeof (WCHAR));
   return wstr;
 }
-
+  
 /* INTERNAL: Since we can't rely on Winelib startup code calling w/getmainargs,
  * we initialise data values during DLL loading. When called by a native
  * program we simply return the data we've already initialised. This also means
@@ -165,9 +263,6 @@
  */
 void msvcrt_init_args(void)
 {
-  char *ptr;
-  WCHAR *wptr;
-  int count;
   DWORD version;
 
   MSVCRT__acmdln = _strdup( GetCommandLineA() );
@@ -198,42 +293,9 @@
 
   /* FIXME: set app type for Winelib apps */
 
-  environ_strings = GetEnvironmentStringsA();
-  count = 1; /* for NULL sentinel */
-  for (ptr = environ_strings; *ptr; ptr += strlen(ptr) + 1)
-  {
-    count++;
-  }
-  MSVCRT__environ = HeapAlloc(GetProcessHeap(), 0, count * sizeof(char*));
-  if (MSVCRT__environ)
-  {
-    count = 0;
-    for (ptr = environ_strings; *ptr; ptr += strlen(ptr) + 1)
-    {
-      MSVCRT__environ[count++] = ptr;
-    }
-    MSVCRT__environ[count] = NULL;
-  }
-
-  MSVCRT___initenv = MSVCRT__environ;
+  MSVCRT___initenv= SnapshotOfEnvironmentA(NULL);
+  MSVCRT___winitenv= SnapshotOfEnvironmentW(NULL);
 
-  wenviron_strings = GetEnvironmentStringsW();
-  count = 1; /* for NULL sentinel */
-  for (wptr = wenviron_strings; *wptr; wptr += lstrlenW(wptr) + 1)
-  {
-    count++;
-  }
-  MSVCRT__wenviron = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WCHAR*));
-  if (MSVCRT__wenviron)
-  {
-    count = 0;
-    for (wptr = wenviron_strings; *wptr; wptr += lstrlenW(wptr) + 1)
-    {
-      MSVCRT__wenviron[count++] = wptr;
-    }
-    MSVCRT__wenviron[count] = NULL;
-  }
-  MSVCRT___winitenv = MSVCRT__wenviron;
 }
 
 
@@ -241,8 +303,10 @@
 void msvcrt_free_args(void)
 {
   /* FIXME: more things to free */
-  FreeEnvironmentStringsA(environ_strings);
-  FreeEnvironmentStringsW(wenviron_strings);
+  if (MSVCRT___initenv) HeapFree(GetProcessHeap(), 0,MSVCRT___initenv);
+  if (MSVCRT__environ) HeapFree(GetProcessHeap(), 0,MSVCRT__environ);
+  if (MSVCRT__environ) HeapFree(GetProcessHeap(), 0,MSVCRT__environ);
+  if (MSVCRT__wenviron) HeapFree(GetProcessHeap(), 0,MSVCRT__wenviron);
 }
 
 /*********************************************************************
Index: wine/dlls/msvcrt/environ.c
===================================================================
RCS file: /home/wine/wine/dlls/msvcrt/environ.c,v
retrieving revision 1.8
diff -u -r1.8 environ.c
--- wine/dlls/msvcrt/environ.c	9 Mar 2002 23:39:08 -0000	1.8
+++ wine/dlls/msvcrt/environ.c	8 Jul 2002 22:10:24 -0000
@@ -86,7 +86,10 @@
   FreeEnvironmentStringsW( environ );
   return NULL;
 }
-
+extern char **MSVCRT___environ;
+extern WCHAR **MSVCRT___wenviron;
+char ** SnapshotOfEnvironmentA(char **);
+WCHAR ** SnapshotOfEnvironmentW(WCHAR **);
 /*********************************************************************
  *		_putenv (MSVCRT.@)
  */
@@ -94,6 +97,7 @@
 {
  char name[256], value[512];
  char *dst = name;
+ int ret;
 
  TRACE("%s\n", str);
 
@@ -109,7 +113,13 @@
   *dst++ = *str++;
  *dst = '\0';
 
- return !SetEnvironmentVariableA(name, value[0] ? value : NULL);
+ ret = !SetEnvironmentVariableA(name, value[0] ? value : NULL);
+ /* Update the __p__environ array only when already initialized */
+ if (MSVCRT___environ)
+   MSVCRT___environ = SnapshotOfEnvironmentA(MSVCRT___environ);
+ if (MSVCRT___wenviron)
+   MSVCRT___wenviron = SnapshotOfEnvironmentW(MSVCRT___wenviron);
+ return ret;
 }
 
 /*********************************************************************
@@ -119,6 +129,7 @@
 {
  WCHAR name[256], value[512];
  WCHAR *dst = name;
+ int ret;
 
  TRACE("%s\n", debugstr_w(str));
 
@@ -134,5 +145,11 @@
   *dst++ = *str++;
  *dst = (WCHAR)L'\0';
 
- return !SetEnvironmentVariableW(name, value[0] ? value : NULL);
+ ret = !SetEnvironmentVariableW(name, value[0] ? value : NULL);
+ /* Update the __p__environ array only when already initialized */
+ if (MSVCRT___environ)
+   MSVCRT___environ = SnapshotOfEnvironmentA(MSVCRT___environ);
+ if (MSVCRT___wenviron)
+   MSVCRT___wenviron = SnapshotOfEnvironmentW(MSVCRT___wenviron);
+ return ret;
 }



More information about the wine-patches mailing list