From: Andrew Nguyen <anguyen@codeweavers.com>
Subject: [1/7] msvcrt: Initialize the environ global variables on DLL load.
Message-Id: <4CA1ABAF.9070500@codeweavers.com>
Date: Tue, 28 Sep 2010 03:47:43 -0500


This fixes bug 24536.
---
 dlls/msvcrt/data.c          |   12 +++-----
 dlls/msvcrt/environ.c       |   14 +++-------
 dlls/msvcrt/tests/environ.c |   61 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 70 insertions(+), 17 deletions(-)

diff --git a/dlls/msvcrt/data.c b/dlls/msvcrt/data.c
index 54dda1c..9082733 100644
--- a/dlls/msvcrt/data.c
+++ b/dlls/msvcrt/data.c
@@ -204,8 +204,6 @@ MSVCRT_wchar_t*** CDECL __p___wargv(void) { return &MSVCRT___wargv; }
  */
 char*** CDECL __p__environ(void)
 {
-  if (!MSVCRT__environ)
-    MSVCRT__environ = msvcrt_SnapshotOfEnvironmentA(NULL);
   return &MSVCRT__environ;
 }
 
@@ -214,8 +212,6 @@ char*** CDECL __p__environ(void)
  */
 MSVCRT_wchar_t*** CDECL __p__wenviron(void)
 {
-  if (!MSVCRT__wenviron)
-    MSVCRT__wenviron = msvcrt_SnapshotOfEnvironmentW(NULL);
   return &MSVCRT__wenviron;
 }
 
@@ -311,9 +307,11 @@ void msvcrt_init_args(void)
   MSVCRT___setlc_active = 0;
   MSVCRT___unguarded_readlc_active = 0;
   MSVCRT__fmode = MSVCRT__O_TEXT;
-  
-  MSVCRT___initenv= msvcrt_SnapshotOfEnvironmentA(NULL);
-  MSVCRT___winitenv= msvcrt_SnapshotOfEnvironmentW(NULL);
+
+  MSVCRT__environ = msvcrt_SnapshotOfEnvironmentA(NULL);
+  MSVCRT__wenviron = msvcrt_SnapshotOfEnvironmentW(NULL);
+  MSVCRT___initenv = msvcrt_SnapshotOfEnvironmentA(NULL);
+  MSVCRT___winitenv = msvcrt_SnapshotOfEnvironmentW(NULL);
 
   MSVCRT__pgmptr = HeapAlloc(GetProcessHeap(), 0, MAX_PATH);
   if (MSVCRT__pgmptr)
diff --git a/dlls/msvcrt/environ.c b/dlls/msvcrt/environ.c
index a60f116..b928dec 100644
--- a/dlls/msvcrt/environ.c
+++ b/dlls/msvcrt/environ.c
@@ -104,11 +104,8 @@ int CDECL _putenv(const char *str)
  /* _putenv returns success on deletion of nonexistent variable, unlike [Rtl]SetEnvironmentVariable */
  if ((ret == -1) && (GetLastError() == ERROR_ENVVAR_NOT_FOUND)) ret = 0;
 
- /* Update the __p__environ array only when already initialized */
- if (MSVCRT__environ)
-   MSVCRT__environ = msvcrt_SnapshotOfEnvironmentA(MSVCRT__environ);
- if (MSVCRT__wenviron)
-   MSVCRT__wenviron = msvcrt_SnapshotOfEnvironmentW(MSVCRT__wenviron);
+ MSVCRT__environ = msvcrt_SnapshotOfEnvironmentA(MSVCRT__environ);
+ MSVCRT__wenviron = msvcrt_SnapshotOfEnvironmentW(MSVCRT__wenviron);
    
 finish:
  HeapFree(GetProcessHeap(), 0, name);
@@ -150,11 +147,8 @@ int CDECL _wputenv(const MSVCRT_wchar_t *str)
  /* _putenv returns success on deletion of nonexistent variable, unlike [Rtl]SetEnvironmentVariable */
  if ((ret == -1) && (GetLastError() == ERROR_ENVVAR_NOT_FOUND)) ret = 0;
 
- /* Update the __p__environ array only when already initialized */
- if (MSVCRT__environ)
-   MSVCRT__environ = msvcrt_SnapshotOfEnvironmentA(MSVCRT__environ);
- if (MSVCRT__wenviron)
-   MSVCRT__wenviron = msvcrt_SnapshotOfEnvironmentW(MSVCRT__wenviron);
+ MSVCRT__environ = msvcrt_SnapshotOfEnvironmentA(MSVCRT__environ);
+ MSVCRT__wenviron = msvcrt_SnapshotOfEnvironmentW(MSVCRT__wenviron);
 
 finish:
  HeapFree(GetProcessHeap(), 0, name);
diff --git a/dlls/msvcrt/tests/environ.c b/dlls/msvcrt/tests/environ.c
index 336238c..8f67010 100644
--- a/dlls/msvcrt/tests/environ.c
+++ b/dlls/msvcrt/tests/environ.c
@@ -42,6 +42,9 @@ static const char *a_very_long_env_string =
  "/usr/lib/mingw32/3.4.2/;"
  "/usr/lib/";
 
+static void (__cdecl *p__getmainargs)(int *, char ***, char ***, int, int *);
+static void (__cdecl *p__wgetmainargs)(int *, wchar_t ***, wchar_t ***, int, int *);
+
 static void test_system(void)
 {
     int ret = system(NULL);
@@ -51,8 +54,66 @@ static void test_system(void)
     ok(ret == 0, "Expected system to return 0, got %d\n", ret);
 }
 
+static void test_environ(void)
+{
+    int argc;
+    char **argv, **envp = NULL;
+    WCHAR **wargv, **wenvp = NULL;
+    int i, mode = 0;
+
+    /* Note that msvcrt from Windows versions older than Vista
+     * expects the mode pointer parameter to be valid.*/
+    if (p__getmainargs)
+        p__getmainargs(&argc, &argv, &envp, 0, &mode);
+    if (p__wgetmainargs)
+        p__wgetmainargs(&argc, &wargv, &wenvp, 0, &mode);
+
+    ok( envp != NULL, "Expected initial environment block pointer to be non-NULL\n" );
+    ok( wenvp != NULL, "Expected initial Unicode environment block pointer to be non-NULL\n" );
+    ok( environ != NULL, "Expected the environ global variable to be initialized on startup\n" );
+    ok( _wenviron != NULL, "Expected the _wenviron global variable to be initialized on startup\n" );
+
+    for (i = 0; ; i++)
+    {
+        if (environ[i])
+        {
+            ok( envp[i] != NULL, "Expected environment block pointer element to be non-NULL\n" );
+            ok( !strcmp(environ[i], envp[i]),
+                "Expected environ and environment block pointer strings (%s vs. %s) to match\n",
+                environ[i], envp[i] );
+        }
+        else
+        {
+            ok( !envp[i], "Expected environment block pointer element to be NULL, got %p\n", envp[i] );
+            break;
+        }
+
+        if (_wenviron[i])
+        {
+            ok( wenvp[i] != NULL, "Expected Unicode environment block pointer element to be non-NULL\n" );
+            ok( !winetest_strcmpW(_wenviron[i], wenvp[i]),
+                "Expected Unicode environ and environment block pointer strings (%s vs. %s) to match\n",
+                wine_dbgstr_w(_wenviron[i]), wine_dbgstr_w(wenvp[i]) );
+        }
+        else
+        {
+            ok( !wenvp[i], "Expected Unicode environment block pointer element to be NULL, got %p\n", envp[i] );
+            break;
+        }
+    }
+}
+
 START_TEST(environ)
 {
+    HMODULE hmod = GetModuleHandleA("msvcrt.dll");
+
+    p__getmainargs = (void *)GetProcAddress(hmod, "__getmainargs");
+    p__wgetmainargs = (void *)GetProcAddress(hmod, "__wgetmainargs");
+    ok( p__getmainargs != NULL, "Expected __getmainargs to be exported in msvcrt\n" );
+    ok( p__wgetmainargs != NULL, "Expected __getmainargs to be exported in msvcrt\n" );
+
+    test_environ();
+
     ok( _putenv("cat=") == 0, "_putenv failed on deletion of nonexistent environment variable\n" );
     ok( _putenv("cat=dog") == 0, "failed setting cat=dog\n" );
     ok( strcmp(getenv("cat"), "dog") == 0, "getenv did not return 'dog'\n" );