diff options
author | James McCoy <jamessan@jamessan.com> | 2021-05-18 06:54:24 -0400 |
---|---|---|
committer | James McCoy <jamessan@jamessan.com> | 2021-05-18 08:53:08 -0400 |
commit | 88ee095d42e222ec2353b1eaae48a2a9a65b1d9d (patch) | |
tree | eeb88f909c265b85c11a5d3364fd7352120f8373 | |
parent | d250905c69c0a8d2ac99c4ade9cfb574a011faaf (diff) | |
download | rneovim-88ee095d42e222ec2353b1eaae48a2a9a65b1d9d.tar.gz rneovim-88ee095d42e222ec2353b1eaae48a2a9a65b1d9d.tar.bz2 rneovim-88ee095d42e222ec2353b1eaae48a2a9a65b1d9d.zip |
fix(job): Deduplicate env var names on Windows
Windows handles environment variable names case-insensitively (i.e.,
%Path% can be accessed via %PATH%). Since nvim explicitly creates the
environment block for jobs, we need to ensure it doesn't contain
duplicate names with different cases (e.g., both %Path% and %PATH%) as
that can confuse processes using the environment.
`f_environ()` now converts all env var names to upper-case on Windows,
since it does duplicate detection and also provides the base environment
for jobs. Similarly, `create_environment()` converts any env var names
supplied in the job opts to upper-case so they can be compared against
what we get from `f_environ()`.
Closes #14541
-rw-r--r-- | src/nvim/eval/funcs.c | 33 |
1 files changed, 31 insertions, 2 deletions
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 072d206ecb..caaf675db2 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -1850,15 +1850,30 @@ static void f_environ(typval_T *argvars, typval_T *rettv, FunPtr fptr) ptrdiff_t len = end - str; assert(len > 0); const char * value = str + len + 1; - if (tv_dict_find(rettv->vval.v_dict, str, len) != NULL) { + + char c = env[i][len]; + env[i][len] = NUL; + +#ifdef WIN32 + // Upper-case all the keys for Windows so we can detect duplicates + char *const key = strcase_save(str, true); +#else + char *const key = xstrdup(str); +#endif + + env[i][len] = c; + + if (tv_dict_find(rettv->vval.v_dict, key, len) != NULL) { // Since we're traversing from the end of the env block to the front, any // duplicate names encountered should be ignored. This preserves the // semantics of env vars defined later in the env block taking precedence. + xfree(key); continue; } tv_dict_add_str(rettv->vval.v_dict, - str, len, + key, len, value); + xfree(key); } os_free_fullenv(env); } @@ -5096,7 +5111,21 @@ static dict_T *create_environment(const dictitem_T *job_env, } if (job_env) { +#ifdef WIN32 + TV_DICT_ITER(job_env->di_tv.vval.v_dict, var, { + // Always use upper-case keys for Windows so we detect duplicate keys + char *const key = strcase_save((const char *)var->di_key, true); + size_t len = strlen(key); + dictitem_T *dv = tv_dict_find(env, key, len); + if (dv) { + tv_dict_item_remove(env, dv); + } + tv_dict_add_str(env, key, len, tv_get_string(&var->di_tv)); + xfree(key); + }); +#else tv_dict_extend(env, job_env->di_tv.vval.v_dict, "force"); +#endif } if (pty) { |