diff --git a/runtime/doc/vimfn.txt b/runtime/doc/vimfn.txt index 7dd9c0595f..e91dad1e2b 100644 --- a/runtime/doc/vimfn.txt +++ b/runtime/doc/vimfn.txt @@ -1877,7 +1877,8 @@ executable({expr}) *executable()* *NoDefaultCurrentDirectoryInExePath* On MS-Windows an executable in Vim's current working directory is also normally found, but this can be disabled by setting - the $NoDefaultCurrentDirectoryInExePath environment variable. + the `$NoDefaultCurrentDirectoryInExePath` environment variable. + This is always done for |:!| commands, for security reasons. The result is a Number: 1 exists diff --git a/runtime/lua/vim/_meta/vimfn.lua b/runtime/lua/vim/_meta/vimfn.lua index 5a2ec2fe84..fc8b1e218f 100644 --- a/runtime/lua/vim/_meta/vimfn.lua +++ b/runtime/lua/vim/_meta/vimfn.lua @@ -1652,7 +1652,8 @@ function vim.fn.eventhandler() end --- *NoDefaultCurrentDirectoryInExePath* --- On MS-Windows an executable in Vim's current working directory --- is also normally found, but this can be disabled by setting ---- the $NoDefaultCurrentDirectoryInExePath environment variable. +--- the `$NoDefaultCurrentDirectoryInExePath` environment variable. +--- This is always done for |:!| commands, for security reasons. --- --- The result is a Number: --- 1 exists diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua index a2cb13a78a..5b36e6c4b7 100644 --- a/src/nvim/eval.lua +++ b/src/nvim/eval.lua @@ -2163,7 +2163,8 @@ M.funcs = { *NoDefaultCurrentDirectoryInExePath* On MS-Windows an executable in Vim's current working directory is also normally found, but this can be disabled by setting - the $NoDefaultCurrentDirectoryInExePath environment variable. + the `$NoDefaultCurrentDirectoryInExePath` environment variable. + This is always done for |:!| commands, for security reasons. The result is a Number: 1 exists diff --git a/src/nvim/os/env.c b/src/nvim/os/env.c index 55a9eabfbb..0bc9a23180 100644 --- a/src/nvim/os/env.c +++ b/src/nvim/os/env.c @@ -1291,3 +1291,19 @@ void vim_setenv_ext(const char *name, const char *val) didset_vimruntime = false; } } + +#ifdef MSWIN +/// Restore a previous environment variable value, or unset it if NULL. +/// "must_free" indicates whether "old_value" was allocated. +void restore_env_var(const char *name, char *old_value, bool must_free) +{ + if (old_value != NULL) { + os_setenv(name, old_value, true); + if (must_free) { + xfree(old_value); + } + return; + } + os_unsetenv(name); +} +#endif diff --git a/src/nvim/os/shell.c b/src/nvim/os/shell.c index f8e10508d8..984027b747 100644 --- a/src/nvim/os/shell.c +++ b/src/nvim/os/shell.c @@ -33,6 +33,7 @@ #include "nvim/message.h" #include "nvim/option_vars.h" #include "nvim/os/fs.h" +#include "nvim/os/os.h" #include "nvim/os/os_defs.h" #include "nvim/os/shell.h" #include "nvim/os/signal.h" @@ -857,6 +858,15 @@ int os_system(char **argv, const char *input, size_t len, char **output, static int do_os_system(char **argv, const char *input, size_t len, char **output, size_t *nread, bool silent, bool forward_output) { + int exitcode = -1; + +#ifdef MSWIN + // do not execute anything from the current directory by setting the + // environemnt variable $NoDefaultCurrentDirectoryInExePath + char *oldval = os_getenv("NoDefaultCurrentDirectoryInExePath"); + os_setenv("NoDefaultCurrentDirectoryInExePath", "1", true); +#endif + out_data_decide_throttle(0); // Initialize throttle decider. out_data_ring(NULL, 0); // Initialize output ring-buffer. bool has_input = (input != NULL && len > 0); @@ -894,8 +904,7 @@ static int do_os_system(char **argv, const char *input, size_t len, char **outpu msg_outtrans(prog, 0, false); msg_putchar('\n'); } - multiqueue_free(events); - return -1; + goto end; } // Note: unlike process events, stream events are not queued, as we want to @@ -917,7 +926,7 @@ static int do_os_system(char **argv, const char *input, size_t len, char **outpu if (!wstream_write(&proc->in, input_buffer)) { // couldn't write, stop the process and tell the user about it proc_stop(proc); - return -1; + goto end; } // close the input stream after everything is written wstream_set_write_cb(&proc->in, shell_write_cb, NULL); @@ -933,7 +942,7 @@ static int do_os_system(char **argv, const char *input, size_t len, char **outpu msg_no_more = true; lines_left = -1; } - int exitcode = proc_wait(proc, -1, NULL); + exitcode = proc_wait(proc, -1, NULL); if (!got_int && out_data_decide_throttle(0)) { // Last chunk of output was skipped; display it now. out_data_ring(NULL, SIZE_MAX); @@ -965,8 +974,14 @@ static int do_os_system(char **argv, const char *input, size_t len, char **outpu } assert(multiqueue_empty(events)); +end: multiqueue_free(events); +#ifdef MSWIN + // Restore original value of NoDefaultCurrentDirectoryInExePath + restore_env_var("NoDefaultCurrentDirectoryInExePath", oldval, true); +#endif + return exitcode; }