From: Andrew Nguyen 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" );