There are certain applications which try to traverse the environement being returned, but this is problematic since they cannot acquire the PEB Lock (i.e cl.exe on Visual Studio 14.15) .
To resolve the issue provide a copy of the current environment same as in GetEnvironmentStringsA .
Signed-off-by: Jon Doron arilou@gmail.com --- dlls/kernel32/environ.c | 27 +++++++++++++++++++++++++-- dlls/kernel32/tests/environ.c | 15 +++++++++++++++ 2 files changed, 40 insertions(+), 2 deletions(-)
diff --git a/dlls/kernel32/environ.c b/dlls/kernel32/environ.c index 99bf706e95..5a5f50340e 100644 --- a/dlls/kernel32/environ.c +++ b/dlls/kernel32/environ.c @@ -139,7 +139,30 @@ LPSTR WINAPI GetEnvironmentStringsA(void) */ LPWSTR WINAPI GetEnvironmentStringsW(void) { - return NtCurrentTeb()->Peb->ProcessParameters->Environment; + LPWSTR ret, ptrW; + unsigned len; + + RtlAcquirePebLock(); + + ptrW = NtCurrentTeb()->Peb->ProcessParameters->Environment; + if (!ptrW || !*ptrW) + { + RtlReleasePebLock(); + return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WCHAR) * 2); + } + + while (*ptrW) + ptrW += strlenW(ptrW) + 1; + + len = (ULONG_PTR)ptrW - (ULONG_PTR)NtCurrentTeb()->Peb->ProcessParameters->Environment; + ret = HeapAlloc(GetProcessHeap(), 0, len + sizeof(WCHAR)); + if (ret) { + memcpy(ret, NtCurrentTeb()->Peb->ProcessParameters->Environment, len); + ret[len / 2] = 0; + } + + RtlReleasePebLock(); + return ret; }
@@ -157,7 +180,7 @@ BOOL WINAPI FreeEnvironmentStringsA( LPSTR ptr ) */ BOOL WINAPI FreeEnvironmentStringsW( LPWSTR ptr ) { - return TRUE; + return HeapFree( GetProcessHeap(), 0, ptr ); }
diff --git a/dlls/kernel32/tests/environ.c b/dlls/kernel32/tests/environ.c index f8452be2ee..4249ea7ebe 100644 --- a/dlls/kernel32/tests/environ.c +++ b/dlls/kernel32/tests/environ.c @@ -554,6 +554,20 @@ static void test_GetComputerNameExW(void) HeapFree(GetProcessHeap(), 0, nameW); }
+static void test_GetEnvironmentStringsW(void) +{ + PWCHAR env1; + PWCHAR env2; + + env1 = GetEnvironmentStringsW(); + env2 = GetEnvironmentStringsW(); + ok(env1 != env2 || + broken(env1 == env2), /* NT <= 5.1 */ + "should return different copies\n"); + FreeEnvironmentStringsW(env1); + FreeEnvironmentStringsW(env2); +} + START_TEST(environ) { init_functionpointers(); @@ -565,4 +579,5 @@ START_TEST(environ) test_GetComputerName(); test_GetComputerNameExA(); test_GetComputerNameExW(); + test_GetEnvironmentStringsW(); }