Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Windows: uv_os_getenv() with empty (but defined) variable #2413

Closed
justinmk opened this issue Aug 10, 2019 · 4 comments · Fixed by #2419
Closed

Windows: uv_os_getenv() with empty (but defined) variable #2413

justinmk opened this issue Aug 10, 2019 · 4 comments · Fixed by #2419
Labels

Comments

@justinmk
Copy link

justinmk commented Aug 10, 2019

  • Version: 1.30.0
  • Platform: Windows 7, building with MSVC 2017 (appveyor)

If an env var is defined as empty:

SetEnvironmentVariable( "foo", "" );

The libuv Windows impl of uv_os_getenv returns -4094 (UV_UNKNOWN).

According to this post,

When GetEnvironmentVariable return 0, it may be that the variable doesn't exist, or that is exists with an empty content. In the later case, GetLastError returns 0.

But libuv checks GetEnvironmentVariableW() == 0, then returns uv_translate_sys_error(0).

libuv/src/win/util.c

Lines 1484 to 1505 in 8ed9112

len = GetEnvironmentVariableW(name_w, var, MAX_ENV_VAR_LENGTH);
uv__free(name_w);
assert(len < MAX_ENV_VAR_LENGTH); /* len does not include the null */
if (len == 0) {
r = GetLastError();
if (r == ERROR_ENVVAR_NOT_FOUND)
return UV_ENOENT;
return uv_translate_sys_error(r);
}
/* Check how much space we need */
bufsize = WideCharToMultiByte(CP_UTF8, 0, var, -1, NULL, 0, NULL, NULL);
if (bufsize == 0) {
return uv_translate_sys_error(GetLastError());
} else if (bufsize > *size) {
*size = bufsize;
return UV_ENOBUFS;
}

It should instead return 0 with buffer size of 0.

justinmk added a commit to justinmk/neovim that referenced this issue Aug 10, 2019
os_env_exists() fails on MSVC build:
    os_env_exists:104: uv_os_getenv(EMPTY_VAR) failed: -4094 UNKNOWN

- Revert 396a394
- HACK: Windows: return TRUE if uv_os_getenv() returns UV_UNKNOWN, until
  libuv bug is fixed: libuv/libuv#2413

ref neovim@396a394#r34642361
justinmk added a commit to neovim/neovim that referenced this issue Aug 10, 2019
os_env_exists() fails on MSVC build:
    os_env_exists:104: uv_os_getenv(EMPTY_VAR) failed: -4094 UNKNOWN

- Revert 396a394
- HACK: Windows: return TRUE if uv_os_getenv() returns UV_UNKNOWN, until
  libuv bug is fixed: libuv/libuv#2413

ref 396a394#r34642361
@cjihrig
Copy link
Contributor

cjihrig commented Aug 10, 2019

So, I wrote cjihrig@3377726, which I expected to be a straightforward fix.

But, there seems to be a second issue. While trying to write a test for this issue, I set an environment variable to the empty string. Windows seems to delete the environment variable instead. There's a good chance I'm doing something wrong, and I don't have a Windows setup to test on, but that's where I'm at currently.

EDIT: It looks like Ruby avoids GetEnvironmentVariable() for this reason: ruby/ruby@2982c52

@saghul
Copy link
Member

saghul commented Aug 11, 2019

@cjihrig What Ruby does looks sensible IMHO. I do have a Windows laptop up and running if you want me to test stuff.

@erw7
Copy link
Contributor

erw7 commented Aug 12, 2019

@cjihrig cjihrig@3377726 and the following patch seems to have fixed the neovim issue. I think GetEnvironmentVariable() doesn't set the last error code to 0 on success.

Ref. https://docs.microsoft.com/en-us/windows/win32/api/errhandlingapi/nf-errhandlingapi-getlasterror

diff --git a/src/win/util.c b/src/win/util.c
index 54cf4f42..2fef4c5c 100644
--- a/src/win/util.c
+++ b/src/win/util.c
@@ -1412,13 +1412,13 @@ int uv_os_getenv(const char* name, char* buffer, size_t* size) {
   if (r != 0)
     return r;

+  SetLastError(ERROR_SUCCESS);
   len = GetEnvironmentVariableW(name_w, var, MAX_ENV_VAR_LENGTH);
+  r = GetLastError();
   uv__free(name_w);
   assert(len < MAX_ENV_VAR_LENGTH); /* len does not include the null */

   if (len == 0) {
-    r = GetLastError();
-
     if (r == ERROR_ENVVAR_NOT_FOUND)
       return UV_ENOENT;

I set an environment variable to the empty string. Windows seems to delete the environment variable instead.

I don't know how you set the environment variable to empty string, but the following code appears to create an empty environment variable.

SetEnvironmentVariableW(L"FOO", L"");
uv_os_setenv("BAR", ""); 

@cjihrig
Copy link
Contributor

cjihrig commented Aug 12, 2019

Thanks @erw7 - calling SetLastError() did the trick. Fix for this issue in #2419.

cjihrig added a commit to cjihrig/libuv that referenced this issue Aug 13, 2019
Fixes: libuv#2413
PR-URL: libuv#2419
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Saúl Ibarra Corretgé <saghul@gmail.com>
cjihrig added a commit to cjihrig/libuv that referenced this issue Aug 13, 2019
uv__convert_utf8_to_utf16() always null terminates its
UTF-16 output. This commit updates the code to use L'\0'
as the terminator, instead of '\0'.

Fixes: libuv#2413
PR-URL: libuv#2419
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Saúl Ibarra Corretgé <saghul@gmail.com>
cjihrig added a commit to cjihrig/libuv that referenced this issue Aug 13, 2019
This commit adds Windows support for retrieving empty
environment variables via uv_os_getenv().

Fixes: libuv#2413
PR-URL: libuv#2419
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Saúl Ibarra Corretgé <saghul@gmail.com>
erw7 pushed a commit to erw7/libuv that referenced this issue Aug 19, 2019
This commit adds Windows support for retrieving empty
environment variables via uv_os_getenv().

Fixes: libuv#2413
PR-URL: libuv#2419
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Saúl Ibarra Corretgé <saghul@gmail.com>
erw7 pushed a commit to erw7/libuv that referenced this issue Aug 19, 2019
uv__convert_utf8_to_utf16() always null terminates its
UTF-16 output. This commit updates the code to use L'\0'
as the terminator, instead of '\0'.

Fixes: libuv#2413
PR-URL: libuv#2419
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Saúl Ibarra Corretgé <saghul@gmail.com>
erw7 pushed a commit to erw7/libuv that referenced this issue Aug 19, 2019
Fixes: libuv#2413
PR-URL: libuv#2419
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Saúl Ibarra Corretgé <saghul@gmail.com>
erw7 pushed a commit to erw7/libuv that referenced this issue Aug 19, 2019
This commit adds Windows support for retrieving empty
environment variables via uv_os_getenv().

Fixes: libuv#2413
PR-URL: libuv#2419
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Saúl Ibarra Corretgé <saghul@gmail.com>
erw7 pushed a commit to erw7/libuv that referenced this issue Aug 19, 2019
uv__convert_utf8_to_utf16() always null terminates its
UTF-16 output. This commit updates the code to use L'\0'
as the terminator, instead of '\0'.

Fixes: libuv#2413
PR-URL: libuv#2419
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Saúl Ibarra Corretgé <saghul@gmail.com>
erw7 pushed a commit to erw7/libuv that referenced this issue Aug 19, 2019
Fixes: libuv#2413
PR-URL: libuv#2419
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Saúl Ibarra Corretgé <saghul@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants