https://bugs.winehq.org/show_bug.cgi?id=48471
Bug ID: 48471 Summary: Mismatching behavior of GetEnvironmentVariableW for empty / long values Product: Wine Version: 5.0-rc4 Hardware: x86 OS: Linux Status: UNCONFIRMED Severity: normal Priority: P2 Component: kernelbase Assignee: wine-bugs@winehq.org Reporter: wine@thecybershadow.net Distribution: ---
Attempting to build the Windows version of DMD, the reference compiler for the D programming language, fails under Wine. This seems to be caused by the following chain of events:
1. The makefile invokes a build program with a "VERBOSE=" on the command-line:
https://github.com/dlang/dmd/blob/49dfbe54f4a0f62a0694aec9fb4184739903a0c2/s...
(Here "$(VERBOSE)" is not set and expands to the empty string.)
2. The build program registers the command-line arguments into the process environment:
https://github.com/dlang/dmd/blob/49dfbe54f4a0f62a0694aec9fb4184739903a0c2/s...
This sets the environment variable VERBOSE to the empty string.
3. Later, it attempts to check if the "VERBOSE" variable is in the environment:
https://github.com/dlang/dmd/blob/49dfbe54f4a0f62a0694aec9fb4184739903a0c2/s...
4. This calls the following Windows code in the standard library to read the environment:
https://github.com/dlang/phobos/blob/e373b4e77448bc11c6e4ea6c85bcdb8f7ab86f2...
5. For empty variables, the code behaves differently in Windows and Wine - Wine's implementation returns 0, while Windows returns 1. As a result, the standard library code throws an exception under Wine.
Writing a test program reveals further differences. The program:
#include <stdio.h> #include <windows.h>
void main() { WCHAR buf[4]; DWORD size; int len, i;
for (len = 0; len <= 2; len++) { for (i = 0; i < len; i++) buf[i] = 'a'; buf[len] = 0;
SetEnvironmentVariableW(L"TESTVAR", buf);
for (i = 0; i <= len + 1; i++) { DWORD err; SetLastError(1); buf[0] = 1; size = GetEnvironmentVariableW(L"TESTVAR", buf, i); err = GetLastError(); printf("%d->%d: size=%d error=%d buf[0]=%d\n", len, i, size, err, buf[0]); } printf("\n"); } }
Output on Windows [Version 10.0.17134.648]:
0->0: size=1 error=1 buf[0]=1 0->1: size=0 error=1 buf[0]=0
1->0: size=2 error=1 buf[0]=1 1->1: size=2 error=1 buf[0]=0 1->2: size=1 error=1 buf[0]=97
2->0: size=3 error=1 buf[0]=1 2->1: size=3 error=1 buf[0]=0 2->2: size=3 error=1 buf[0]=0 2->3: size=2 error=1 buf[0]=97
Output on Wine:
0->0: size=0 error=1 buf[0]=1 0->1: size=0 error=1 buf[0]=0
1->0: size=2 error=122 buf[0]=1 1->1: size=2 error=122 buf[0]=1 1->2: size=1 error=1 buf[0]=97
2->0: size=3 error=122 buf[0]=1 2->1: size=3 error=122 buf[0]=1 2->2: size=3 error=122 buf[0]=1 2->3: size=2 error=1 buf[0]=97
We can observe these differences:
1. Wine returns 0 and not 1 when the variable is empty and the function is given a zero-length buffer.
2. Wine sets the last error to ERROR_INSUFFICIENT_BUFFER, while Windows doesn't.
3. Windows zeroes the buffer if the size is non-zero but still insufficient to hold the value. (This is not a bug as the behavior is specified in the documentation to be undefined.)