From 7f50c692685c92d47e6ba6c3ee5f6fdccb78fec5 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Fri, 31 Jul 2020 01:17:24 -0400 Subject: Use dict_T to pass env vars to process spawning code Co-authored-by: Matthieu Coudron --- src/nvim/channel.c | 12 ++++-- src/nvim/eval/funcs.c | 54 +++++++++----------------- src/nvim/eval/typval.c | 27 +++++++++++++ src/nvim/event/libuv_process.c | 7 +++- src/nvim/event/process.h | 3 +- src/nvim/os/pty_process_unix.c | 79 ++++++++++++++++++++++++++++----------- test/functional/core/job_spec.lua | 14 +++++++ 7 files changed, 133 insertions(+), 63 deletions(-) diff --git a/src/nvim/channel.c b/src/nvim/channel.c index 37cbfb968b..5628ede2e6 100644 --- a/src/nvim/channel.c +++ b/src/nvim/channel.c @@ -304,7 +304,8 @@ Channel *channel_job_start(char **argv, CallbackReader on_stdout, bool pty, bool rpc, bool overlapped, bool detach, const char *cwd, uint16_t pty_width, uint16_t pty_height, - char *term_name, char **env, varnumber_T *status_out) + char *term_name, dict_T *env, + varnumber_T *status_out) { assert(cwd == NULL || os_isdir_executable(cwd)); @@ -358,7 +359,9 @@ Channel *channel_job_start(char **argv, CallbackReader on_stdout, if (status) { EMSG3(_(e_jobspawn), os_strerror(status), cmd); xfree(cmd); - os_free_fullenv(proc->env); + if (proc->env) { + tv_dict_free(proc->env); + } if (proc->type == kProcessTypePty) { xfree(chan->stream.pty.term_name); } @@ -367,8 +370,9 @@ Channel *channel_job_start(char **argv, CallbackReader on_stdout, return NULL; } xfree(cmd); - os_free_fullenv(proc->env); - + if (proc->env) { + tv_dict_free(proc->env); + } wstream_init(&proc->in, 0); if (has_out) { diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 8235d74cbb..04e539d309 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -4887,7 +4887,7 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv, FunPtr fptr) bool executable = true; char **argv = tv_to_argv(&argvars[0], NULL, &executable); - char **env = NULL; + dict_T *env = NULL; if (!argv) { rettv->vval.v_number = executable ? 0 : -1; return; // Did error message in tv_to_argv. @@ -4936,7 +4936,7 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv, FunPtr fptr) #endif char *new_cwd = tv_dict_get_string(job_opts, "cwd", false); - if (new_cwd && strlen(new_cwd) > 0) { + if (new_cwd && *new_cwd != NUL) { cwd = new_cwd; // The new cwd must be a directory. if (!os_isdir_executable((const char *)cwd)) { @@ -4945,48 +4945,30 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv, FunPtr fptr) return; } } - dictitem_T *job_env = tv_dict_find(job_opts, S_LEN("env")); - if (job_env) { - if (job_env->di_tv.v_type != VAR_DICT) { - EMSG2(_(e_invarg2), "env"); - shell_free_argv(argv); - return; - } - - size_t custom_env_size = (size_t)tv_dict_len(job_env->di_tv.vval.v_dict); - size_t i = 0; - size_t env_size = 0; - - if (clear_env) { - // + 1 for last null entry - env = xmalloc((custom_env_size + 1) * sizeof(*env)); - env_size = 0; - } else { - env_size = os_get_fullenv_size(); - env = xmalloc((custom_env_size + env_size + 1) * sizeof(*env)); - - os_copy_fullenv(env, env_size); - i = env_size; - } - assert(env); // env must be allocated at this point + dictitem_T *job_env = tv_dict_find(job_opts, S_LEN("env")); + if (job_env && job_env->di_tv.v_type != VAR_DICT) { + EMSG2(_(e_invarg2), "env"); + shell_free_argv(argv); + return; + } - TV_DICT_ITER(job_env->di_tv.vval.v_dict, var, { - const char *str = tv_get_string(&var->di_tv); - assert(str); - size_t len = STRLEN(var->di_key) + strlen(str) + strlen("=") + 1; - env[i] = xmalloc(len); - snprintf(env[i], len, "%s=%s", (char *)var->di_key, str); - i++; - }); + env = tv_dict_alloc(); - // must be null terminated - env[env_size + custom_env_size] = NULL; + if (!clear_env) { + typval_T temp_env = TV_INITIAL_VALUE; + f_environ(NULL, &temp_env, NULL); + tv_dict_extend(env, temp_env.vval.v_dict, "force"); + tv_dict_free(temp_env.vval.v_dict); } + if (job_env) { + tv_dict_extend(env, job_env->di_tv.vval.v_dict, "force"); + } if (!common_job_callbacks(job_opts, &on_stdout, &on_stderr, &on_exit)) { shell_free_argv(argv); + tv_dict_free(env); return; } } diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c index 02d32a4f86..2f8776def4 100644 --- a/src/nvim/eval/typval.c +++ b/src/nvim/eval/typval.c @@ -1523,6 +1523,33 @@ varnumber_T tv_dict_get_number(const dict_T *const d, const char *const key) return tv_get_number(&di->di_tv); } +/// Converts a dict to an environment +/// +/// +char **tv_dict_to_env(dict_T *denv) +{ + size_t env_size = (size_t)tv_dict_len(denv); + + size_t i = 0; + char **env = NULL; + + // + 1 for NULL + env = xmalloc((env_size + 1) * sizeof(*env)); + + TV_DICT_ITER(denv, var, { + const char *str = tv_get_string(&var->di_tv); + assert(str); + size_t len = STRLEN(var->di_key) + strlen(str) + strlen("=") + 1; + env[i] = xmalloc(len); + snprintf(env[i], len, "%s=%s", (char *)var->di_key, str); + i++; + }); + + // must be null terminated + env[env_size] = NULL; + return env; +} + /// Get a string item from a dictionary /// /// @param[in] d Dictionary to get item from. diff --git a/src/nvim/event/libuv_process.c b/src/nvim/event/libuv_process.c index 13517d3df1..72e45878f6 100644 --- a/src/nvim/event/libuv_process.c +++ b/src/nvim/event/libuv_process.c @@ -41,7 +41,6 @@ int libuv_process_spawn(LibuvProcess *uvproc) #endif uvproc->uvopts.exit_cb = exit_cb; uvproc->uvopts.cwd = proc->cwd; - uvproc->uvopts.env = proc->env; uvproc->uvopts.stdio = uvproc->uvstdio; uvproc->uvopts.stdio_count = 3; uvproc->uvstdio[0].flags = UV_IGNORE; @@ -49,6 +48,12 @@ int libuv_process_spawn(LibuvProcess *uvproc) uvproc->uvstdio[2].flags = UV_IGNORE; uvproc->uv.data = proc; + if (proc->env) { + uvproc->uvopts.env = tv_dict_to_env(proc->env); + } else { + uvproc->uvopts.env = NULL; + } + if (!proc->in.closed) { uvproc->uvstdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE; #ifdef WIN32 diff --git a/src/nvim/event/process.h b/src/nvim/event/process.h index 84e81238e9..24debdb276 100644 --- a/src/nvim/event/process.h +++ b/src/nvim/event/process.h @@ -4,6 +4,7 @@ #include "nvim/event/loop.h" #include "nvim/event/rstream.h" #include "nvim/event/wstream.h" +#include "nvim/eval/typval.h" typedef enum { kProcessTypeUv, @@ -23,7 +24,7 @@ struct process { uint64_t stopped_time; // process_stop() timestamp const char *cwd; char **argv; - char **env; + dict_T *env; Stream in, out, err; process_exit_cb cb; internal_process_cb internal_exit_cb, internal_close_cb; diff --git a/src/nvim/os/pty_process_unix.c b/src/nvim/os/pty_process_unix.c index 4d7d9a45df..a3c9e726c5 100644 --- a/src/nvim/os/pty_process_unix.c +++ b/src/nvim/os/pty_process_unix.c @@ -20,6 +20,10 @@ # include #endif +#ifdef __APPLE__ +# include +#endif + #include #include "nvim/lib/klist.h" @@ -151,31 +155,24 @@ void pty_process_teardown(Loop *loop) uv_signal_stop(&loop->children_watcher); } +static const char *ignored_env_vars[] = { + "COLUMNS", + "LINES", + "TERMCAP", + "COLORFGBG" +}; + static void init_child(PtyProcess *ptyproc) FUNC_ATTR_NONNULL_ALL { +#if defined(HAVE__NSGETENVIRON) + char **environ = *_NSGetEnviron(); +#else + extern char **environ; +#endif // New session/process-group. #6530 setsid(); - os_unsetenv("COLUMNS"); - os_unsetenv("LINES"); - os_unsetenv("TERMCAP"); - os_unsetenv("COLORFGBG"); - // setting COLORTERM to "truecolor" if termguicolors is set and 256 - // otherwise, but only if it was set in the parent terminal at all - if (os_env_exists("COLORTERM")) { - const char *colorterm = os_getenv("COLORTERM"); - if (colorterm != NULL) { - if (p_tgc) { - os_setenv("COLORTERM", "truecolor", 1); - } else { - os_setenv("COLORTERM", "256", 1); - } - } else { - os_unsetenv("COLORTERM"); - } - } - signal(SIGCHLD, SIG_DFL); signal(SIGHUP, SIG_DFL); signal(SIGINT, SIG_DFL); @@ -190,9 +187,49 @@ static void init_child(PtyProcess *ptyproc) } char *prog = ptyproc->process.argv[0]; - os_setenv("TERM", ptyproc->term_name ? ptyproc->term_name : "ansi", 1); - execvp(prog, ptyproc->process.argv); + if (proc->env) { + for (size_t i = 0; i < ARRAY_SIZE(ignored_env_vars); i++) { + dictitem_T *dv = tv_dict_find(proc->env, ignored_env_vars[i], -1); + if (dv) { + tv_dict_item_remove(proc->env, dv); + } + } + tv_dict_add_str(proc->env, S_LEN("TERM"), ptyproc->term_name ? ptyproc->term_name : "ansi"); + + // setting COLORTERM to "truecolor" if termguicolors is set and 256 + // otherwise, but only if it was set in the parent terminal at all + dictitem_T *dv = tv_dict_find(proc->env, S_LEN("COLORTERM")); + if (dv) { + tv_dict_item_remove(proc->env, dv); + tv_dict_add_str(proc->env, S_LEN("COLORTERM"), p_tgc ? "truecolor" : "256"); + } + + environ = tv_dict_to_env(proc->env); + } else { + for (size_t i = 0; i < ARRAY_SIZE(ignored_env_vars); i++) { + os_unsetenv(ignored_env_vars[i]); + } + + // setting COLORTERM to "truecolor" if termguicolors is set and 256 + // otherwise, but only if it was set in the parent terminal at all + if (os_env_exists("COLORTERM")) { + const char *colorterm = os_getenv("COLORTERM"); + if (colorterm != NULL) { + if (p_tgc) { + os_setenv("COLORTERM", "truecolor", 1); + } else { + os_setenv("COLORTERM", "256", 1); + } + } else { + os_unsetenv("COLORTERM"); + } + } + + os_setenv("TERM", ptyproc->term_name ? ptyproc->term_name : "ansi", 1); + } + execvp(prog, proc->argv); ELOG("execvp failed: %s: %s", strerror(errno), prog); + _exit(122); // 122 is EXEC_FAILED in the Vim source. } diff --git a/test/functional/core/job_spec.lua b/test/functional/core/job_spec.lua index 6d1182478a..3f7595c149 100644 --- a/test/functional/core/job_spec.lua +++ b/test/functional/core/job_spec.lua @@ -75,6 +75,20 @@ describe('jobs', function() }) end) + it('append environment with pty #env', function() + nvim('command', "let $VAR = 'abc'") + nvim('command', "let g:job_opts.pty = v:true") + nvim('command', "let g:job_opts.env = {'TOTO': 'hello world'}") + if iswin() then + nvim('command', [[call jobstart('echo %TOTO% %VAR%', g:job_opts)]]) + else + nvim('command', [[call jobstart('echo $TOTO $VAR', g:job_opts)]]) + end + expect_msg_seq({ + {'notification', 'stdout', {0, {'hello world abc', ''}}}, + }) + end) + it('replace environment #env', function() nvim('command', "let $VAR = 'abc'") nvim('command', "let g:job_opts.env = {'TOTO': 'hello world'}") -- cgit From ef7c6b972a1100fc5b173b7273f2c29017557669 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Thu, 10 Sep 2020 06:31:00 -0400 Subject: Support specifying "env" option for termopen() Co-authored-by: erw7 --- src/nvim/eval/funcs.c | 52 +++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 14 deletions(-) diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 04e539d309..61f14b41e3 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -4875,6 +4875,24 @@ static void f_jobresize(typval_T *argvars, typval_T *rettv, FunPtr fptr) rettv->vval.v_number = 1; } +static dict_T *create_environment(const dictitem_T *job_env, const bool clear_env) +{ + dict_T * env = tv_dict_alloc(); + + if (!clear_env) { + typval_T temp_env = TV_INITIAL_VALUE; + f_environ(NULL, &temp_env, NULL); + tv_dict_extend(env, temp_env.vval.v_dict, "force"); + tv_dict_free(temp_env.vval.v_dict); + } + + if (job_env) { + tv_dict_extend(env, job_env->di_tv.vval.v_dict, "force"); + } + + return env; +} + // "jobstart()" function static void f_jobstart(typval_T *argvars, typval_T *rettv, FunPtr fptr) { @@ -4953,18 +4971,7 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv, FunPtr fptr) return; } - env = tv_dict_alloc(); - - if (!clear_env) { - typval_T temp_env = TV_INITIAL_VALUE; - f_environ(NULL, &temp_env, NULL); - tv_dict_extend(env, temp_env.vval.v_dict, "force"); - tv_dict_free(temp_env.vval.v_dict); - } - - if (job_env) { - tv_dict_extend(env, job_env->di_tv.vval.v_dict, "force"); - } + env = create_environment(job_env, clear_env); if (!common_job_callbacks(job_opts, &on_stdout, &on_stderr, &on_exit)) { shell_free_argv(argv); @@ -10500,6 +10507,8 @@ static void f_termopen(typval_T *argvars, typval_T *rettv, FunPtr fptr) Callback on_exit = CALLBACK_NONE; dict_T *job_opts = NULL; const char *cwd = "."; + dict_T *env = NULL; + if (argvars[1].v_type == VAR_DICT) { job_opts = argvars[1].vval.v_dict; @@ -10514,17 +10523,32 @@ static void f_termopen(typval_T *argvars, typval_T *rettv, FunPtr fptr) } } + dictitem_T *job_env = tv_dict_find(job_opts, S_LEN("env")); + if (job_env && job_env->di_tv.v_type != VAR_DICT) { + EMSG2(_(e_invarg2), "env"); + shell_free_argv(argv); + return; + } + + bool clear_env = tv_dict_get_number(job_opts, "clear_env") != 0; + + env = create_environment(job_env, clear_env); + if (!common_job_callbacks(job_opts, &on_stdout, &on_stderr, &on_exit)) { shell_free_argv(argv); return; } } + const bool pty = true; + const bool rpc = false; + const bool overlapped = false; + const bool detach = false; uint16_t term_width = MAX(0, curwin->w_width_inner - win_col_off(curwin)); Channel *chan = channel_job_start(argv, on_stdout, on_stderr, on_exit, - true, false, false, false, cwd, + pty, rpc, overlapped, detach, cwd, term_width, curwin->w_height_inner, - xstrdup("xterm-256color"), NULL, + xstrdup("xterm-256color"), env, &rettv->vval.v_number); if (rettv->vval.v_number <= 0) { return; -- cgit From 8eec9c7d5b398918609d8edfed3928e873fa646f Mon Sep 17 00:00:00 2001 From: James McCoy Date: Thu, 10 Sep 2020 07:15:32 -0400 Subject: Common handling of required/ignored env vars When starting a pty job, there are certain env vars that we need to either add or remove. Currently, there are two relevant scenarios. * Removing irrelevant env vars on Unix, mostly related to the terminal hosting nvim since they do not apply to a libvterm-hosted terminal. * Adding required env vars for Windows jobs. --- src/nvim/eval/funcs.c | 93 +++++++++++++++++++++++++++++++++++++----- src/nvim/event/libuv_process.c | 7 ++++ src/nvim/os/pty_process_unix.c | 50 ++--------------------- 3 files changed, 94 insertions(+), 56 deletions(-) diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 61f14b41e3..4486cd8f0d 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -4875,7 +4875,38 @@ static void f_jobresize(typval_T *argvars, typval_T *rettv, FunPtr fptr) rettv->vval.v_number = 1; } -static dict_T *create_environment(const dictitem_T *job_env, const bool clear_env) +static const char *ignored_env_vars[] = { +#ifndef WIN32 + "COLUMNS", + "LINES", + "TERMCAP", + "COLORFGBG", +#endif + NULL +}; + +/// According to comments in src/win/process.c of libuv, Windows has a few +/// "essential" environment variables. +static const char *required_env_vars[] = { +#ifdef WIN32 + "HOMEDRIVE", + "HOMEPATH", + "LOGONSERVER", + "PATH", + "SYSTEMDRIVE", + "SYSTEMROOT", + "TEMP", + "USERDOMAIN", + "USERNAME", + "USERPROFILE", + "WINDIR", +#endif + NULL +}; + +static dict_T *create_environment(const dictitem_T *job_env, + const bool clear_env, + const bool pty) { dict_T * env = tv_dict_alloc(); @@ -4884,12 +4915,52 @@ static dict_T *create_environment(const dictitem_T *job_env, const bool clear_en f_environ(NULL, &temp_env, NULL); tv_dict_extend(env, temp_env.vval.v_dict, "force"); tv_dict_free(temp_env.vval.v_dict); + + if (pty) { + // These environment variables generally shouldn't be propagated to the + // child process. We're removing them here so the user can still decide + // they want to explicitly set them. + for (size_t i = 0; + i < ARRAY_SIZE(ignored_env_vars) && ignored_env_vars[i]; + i++) { + dictitem_T *dv = tv_dict_find(env, ignored_env_vars[i], -1); + if (dv) { + tv_dict_item_remove(env, dv); + } + } +#ifndef WIN32 + // Set COLORTERM to "truecolor" if termguicolors is set and 256 + // otherwise, but only if it was set in the parent terminal at all + dictitem_T *dv = tv_dict_find(env, S_LEN("COLORTERM")); + if (dv) { + tv_dict_item_remove(env, dv); + tv_dict_add_str(env, S_LEN("COLORTERM"), p_tgc ? "truecolor" : "256"); + } +#endif + } } if (job_env) { tv_dict_extend(env, job_env->di_tv.vval.v_dict, "force"); } + if (pty) { + // Now that the custom environment is configured, we need to ensure certain + // environment variables are present. + for (size_t i = 0; + i < ARRAY_SIZE(required_env_vars) && required_env_vars[i]; + i++) { + size_t len = strlen(required_env_vars[i]); + dictitem_T *dv = tv_dict_find(env, required_env_vars[i], len); + if (!dv) { + const char *env_var = os_getenv(required_env_vars[i]); + if (env_var) { + tv_dict_add_str(env, required_env_vars[i], len, env_var); + } + } + } + } + return env; } @@ -4929,6 +5000,7 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv, FunPtr fptr) on_stderr = CALLBACK_READER_INIT; Callback on_exit = CALLBACK_NONE; char *cwd = NULL; + dictitem_T *job_env = NULL; if (argvars[1].v_type == VAR_DICT) { job_opts = argvars[1].vval.v_dict; @@ -4964,22 +5036,21 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv, FunPtr fptr) } } - dictitem_T *job_env = tv_dict_find(job_opts, S_LEN("env")); + job_env = tv_dict_find(job_opts, S_LEN("env")); if (job_env && job_env->di_tv.v_type != VAR_DICT) { EMSG2(_(e_invarg2), "env"); shell_free_argv(argv); return; } - env = create_environment(job_env, clear_env); - if (!common_job_callbacks(job_opts, &on_stdout, &on_stderr, &on_exit)) { shell_free_argv(argv); - tv_dict_free(env); return; } } + env = create_environment(job_env, clear_env, pty); + uint16_t width = 0, height = 0; char *term_name = NULL; @@ -10508,6 +10579,9 @@ static void f_termopen(typval_T *argvars, typval_T *rettv, FunPtr fptr) dict_T *job_opts = NULL; const char *cwd = "."; dict_T *env = NULL; + const bool pty = true; + bool clear_env = false; + dictitem_T *job_env = NULL; if (argvars[1].v_type == VAR_DICT) { job_opts = argvars[1].vval.v_dict; @@ -10523,16 +10597,14 @@ static void f_termopen(typval_T *argvars, typval_T *rettv, FunPtr fptr) } } - dictitem_T *job_env = tv_dict_find(job_opts, S_LEN("env")); + job_env = tv_dict_find(job_opts, S_LEN("env")); if (job_env && job_env->di_tv.v_type != VAR_DICT) { EMSG2(_(e_invarg2), "env"); shell_free_argv(argv); return; } - bool clear_env = tv_dict_get_number(job_opts, "clear_env") != 0; - - env = create_environment(job_env, clear_env); + clear_env = tv_dict_get_number(job_opts, "clear_env") != 0; if (!common_job_callbacks(job_opts, &on_stdout, &on_stderr, &on_exit)) { shell_free_argv(argv); @@ -10540,7 +10612,8 @@ static void f_termopen(typval_T *argvars, typval_T *rettv, FunPtr fptr) } } - const bool pty = true; + env = create_environment(job_env, clear_env, pty); + const bool rpc = false; const bool overlapped = false; const bool detach = false; diff --git a/src/nvim/event/libuv_process.c b/src/nvim/event/libuv_process.c index 72e45878f6..0b1ecb12e2 100644 --- a/src/nvim/event/libuv_process.c +++ b/src/nvim/event/libuv_process.c @@ -83,6 +83,9 @@ int libuv_process_spawn(LibuvProcess *uvproc) int status; if ((status = uv_spawn(&proc->loop->uv, &uvproc->uv, &uvproc->uvopts))) { ELOG("uv_spawn failed: %s", uv_strerror(status)); + if (uvproc->uvopts.env) { + os_free_fullenv(uvproc->uvopts.env); + } return status; } @@ -102,6 +105,10 @@ static void close_cb(uv_handle_t *handle) if (proc->internal_close_cb) { proc->internal_close_cb(proc); } + LibuvProcess *uvproc = (LibuvProcess *)proc; + if (uvproc->uvopts.env) { + os_free_fullenv(uvproc->uvopts.env); + } } static void exit_cb(uv_process_t *handle, int64_t status, int term_signal) diff --git a/src/nvim/os/pty_process_unix.c b/src/nvim/os/pty_process_unix.c index a3c9e726c5..0733589870 100644 --- a/src/nvim/os/pty_process_unix.c +++ b/src/nvim/os/pty_process_unix.c @@ -155,13 +155,6 @@ void pty_process_teardown(Loop *loop) uv_signal_stop(&loop->children_watcher); } -static const char *ignored_env_vars[] = { - "COLUMNS", - "LINES", - "TERMCAP", - "COLORFGBG" -}; - static void init_child(PtyProcess *ptyproc) FUNC_ATTR_NONNULL_ALL { @@ -187,46 +180,11 @@ static void init_child(PtyProcess *ptyproc) } char *prog = ptyproc->process.argv[0]; - if (proc->env) { - for (size_t i = 0; i < ARRAY_SIZE(ignored_env_vars); i++) { - dictitem_T *dv = tv_dict_find(proc->env, ignored_env_vars[i], -1); - if (dv) { - tv_dict_item_remove(proc->env, dv); - } - } - tv_dict_add_str(proc->env, S_LEN("TERM"), ptyproc->term_name ? ptyproc->term_name : "ansi"); - - // setting COLORTERM to "truecolor" if termguicolors is set and 256 - // otherwise, but only if it was set in the parent terminal at all - dictitem_T *dv = tv_dict_find(proc->env, S_LEN("COLORTERM")); - if (dv) { - tv_dict_item_remove(proc->env, dv); - tv_dict_add_str(proc->env, S_LEN("COLORTERM"), p_tgc ? "truecolor" : "256"); - } - - environ = tv_dict_to_env(proc->env); - } else { - for (size_t i = 0; i < ARRAY_SIZE(ignored_env_vars); i++) { - os_unsetenv(ignored_env_vars[i]); - } - - // setting COLORTERM to "truecolor" if termguicolors is set and 256 - // otherwise, but only if it was set in the parent terminal at all - if (os_env_exists("COLORTERM")) { - const char *colorterm = os_getenv("COLORTERM"); - if (colorterm != NULL) { - if (p_tgc) { - os_setenv("COLORTERM", "truecolor", 1); - } else { - os_setenv("COLORTERM", "256", 1); - } - } else { - os_unsetenv("COLORTERM"); - } - } - os_setenv("TERM", ptyproc->term_name ? ptyproc->term_name : "ansi", 1); - } + assert(proc->env); + tv_dict_add_str(proc->env, S_LEN("TERM"), + ptyproc->term_name ? ptyproc->term_name : "ansi"); + environ = tv_dict_to_env(proc->env); execvp(prog, proc->argv); ELOG("execvp failed: %s: %s", strerror(errno), prog); -- cgit From a54ac073fb0a636717cdd8791e043d301a642726 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Mon, 28 Sep 2020 23:05:48 -0400 Subject: eval/environ: Prefer the last definition of an env var It's possible for the environment variable block given to nvim to contain multiple definitions for the same env var. In this case, nvim should preserve the last one defined. --- src/nvim/eval/funcs.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 4486cd8f0d..7121d413ea 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -1798,7 +1798,7 @@ static void f_environ(typval_T *argvars, typval_T *rettv, FunPtr fptr) os_copy_fullenv(env, env_size); - for (size_t i = 0; i < env_size; i++) { + for (ssize_t i = env_size - 1; i >= 0; i--) { const char * str = env[i]; const char * const end = strchr(str + (str[0] == '=' ? 1 : 0), '='); @@ -1806,6 +1806,12 @@ 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) { + // 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. + continue; + } tv_dict_add_str(rettv->vval.v_dict, str, len, value); -- cgit From a199363be246dc097b74abfe2703c5058aa8ad45 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Mon, 28 Dec 2020 20:40:07 -0500 Subject: Pass environment on to pty processes on Windows vim-patch:8.2.0239: MS-Windows: 'env' job option does not override existing vars Problem: MS-Windows: 'env' job option does not override existing environment variables. (Tim Pope) Solution: Set the environment variables later. (Yasuhiro Matsumoto, closes vim/vim#5485, closes vim/vim#5608) https://github.com/vim/vim/commit/355757aed6ae2ae5446882570d89f243e4805937 Co-authored-by: erw7 --- src/nvim/os/pty_process_win.c | 78 ++++++++++++++++++++++++++++++++++++++- test/functional/core/job_spec.lua | 4 +- 2 files changed, 78 insertions(+), 4 deletions(-) diff --git a/src/nvim/os/pty_process_win.c b/src/nvim/os/pty_process_win.c index 6f7100e846..52d2f84ace 100644 --- a/src/nvim/os/pty_process_win.c +++ b/src/nvim/os/pty_process_win.c @@ -52,6 +52,7 @@ int pty_process_spawn(PtyProcess *ptyproc) uv_connect_t *out_req = NULL; wchar_t *cmd_line = NULL; wchar_t *cwd = NULL; + wchar_t *env = NULL; const char *emsg = NULL; assert(proc->err.closed); @@ -124,13 +125,22 @@ int pty_process_spawn(PtyProcess *ptyproc) goto cleanup; } + if (proc->env != NULL) { + status = build_env_block(proc->env, &env); + } + + if (status != 0) { + emsg = "build_env_block failed"; + goto cleanup; + } + if (ptyproc->type == kConpty) { if (!os_conpty_spawn(conpty_object, &process_handle, NULL, cmd_line, cwd, - NULL)) { + env)) { emsg = "os_conpty_spawn failed"; status = (int)GetLastError(); goto cleanup; @@ -141,7 +151,7 @@ int pty_process_spawn(PtyProcess *ptyproc) NULL, // Optional application name cmd_line, cwd, - NULL, // Optional environment variables + env, &err); if (spawncfg == NULL) { emsg = "winpty_spawn_config_new failed"; @@ -213,6 +223,7 @@ cleanup: xfree(in_req); xfree(out_req); xfree(cmd_line); + xfree(env); xfree(cwd); return status; } @@ -454,3 +465,66 @@ int translate_winpty_error(int winpty_errno) default: return UV_UNKNOWN; } } + +typedef struct EnvNode { + wchar_t *str; + size_t len; + QUEUE node; +} EnvNode; + +/// Build the environment block to pass to CreateProcessW. +/// +/// @param[in] denv Dict of environment name/value pairs +/// @param[out] env Allocated environment block +/// +/// @returns zero on success or error code of MultiByteToWideChar function. +static int build_env_block(dict_T *denv, wchar_t **env_block) +{ + const size_t denv_size = (size_t)tv_dict_len(denv); + size_t env_block_len = 0; + int rc; + char **env = tv_dict_to_env(denv); + + QUEUE *q; + QUEUE env_q; + QUEUE_INIT(&env_q); + // Convert env vars to wchar_t and calculate how big the final env block + // needs to be + for (size_t i = 0; i < denv_size; i++) { + EnvNode *env_node = xmalloc(sizeof(*env_node)); + rc = utf8_to_utf16(env[i], -1, &env_node->str); + if (rc != 0) { + goto cleanup; + } + env_node->len = wcslen(env_node->str) + 1; + env_block_len += env_node->len; + QUEUE_INSERT_TAIL(&env_q, &env_node->node); + } + + // Additional '\0' after the final entry + env_block_len++; + + *env_block = xmalloc(sizeof(**env_block) * env_block_len); + wchar_t *pos = *env_block; + + QUEUE_FOREACH(q, &env_q) { + EnvNode *env_node = QUEUE_DATA(q, EnvNode, node); + memcpy(pos, env_node->str, env_node->len * sizeof(*pos)); + pos += env_node->len; + } + + *pos = L'\0'; + +cleanup: + q = QUEUE_HEAD(&env_q); + while (q != &env_q) { + QUEUE *next = q->next; + EnvNode *env_node = QUEUE_DATA(q, EnvNode, node); + XFREE_CLEAR(env_node->str); + QUEUE_REMOVE(q); + xfree(env_node); + q = next; + } + + return rc; +} diff --git a/test/functional/core/job_spec.lua b/test/functional/core/job_spec.lua index 3f7595c149..69b221d7e4 100644 --- a/test/functional/core/job_spec.lua +++ b/test/functional/core/job_spec.lua @@ -31,9 +31,9 @@ describe('jobs', function() nvim('set_var', 'channel', channel) source([[ function! Normalize(data) abort - " Windows: remove ^M + " Windows: remove ^M and term escape sequences return type([]) == type(a:data) - \ ? map(a:data, 'substitute(v:val, "\r", "", "g")') + \ ? map(a:data, 'substitute(substitute(v:val, "\r", "", "g"), "\x1b\\%(\\]\\d\\+;.\\{-}\x07\\|\\[.\\{-}[\x40-\x7E]\\)", "", "g")') \ : a:data endfunction function! OnEvent(id, data, event) dict -- cgit From db734ae99463c498309bc8830f902fb65c6523f3 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Mon, 28 Dec 2020 20:48:15 -0500 Subject: test(job): Ensure job-specific env var overrides global env var --- test/functional/core/job_spec.lua | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/functional/core/job_spec.lua b/test/functional/core/job_spec.lua index 69b221d7e4..b59d87eb12 100644 --- a/test/functional/core/job_spec.lua +++ b/test/functional/core/job_spec.lua @@ -63,6 +63,7 @@ describe('jobs', function() it('append environment #env', function() nvim('command', "let $VAR = 'abc'") + nvim('command', "let $TOTO = 'goodbye world'") nvim('command', "let g:job_opts.env = {'TOTO': 'hello world'}") if iswin() then nvim('command', [[call jobstart('echo %TOTO% %VAR%', g:job_opts)]]) @@ -77,6 +78,7 @@ describe('jobs', function() it('append environment with pty #env', function() nvim('command', "let $VAR = 'abc'") + nvim('command', "let $TOTO = 'goodbye world'") nvim('command', "let g:job_opts.pty = v:true") nvim('command', "let g:job_opts.env = {'TOTO': 'hello world'}") if iswin() then @@ -91,6 +93,7 @@ describe('jobs', function() it('replace environment #env', function() nvim('command', "let $VAR = 'abc'") + nvim('command', "let $TOTO = 'goodbye world'") nvim('command', "let g:job_opts.env = {'TOTO': 'hello world'}") nvim('command', "let g:job_opts.clear_env = 1") -- cgit From 035ee868ae2d9cbbf2a290ca3412946fade20833 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Sun, 31 Jan 2021 07:49:31 -0500 Subject: fix(pty_proc/macOS): Properly set the environment for the child Binding _NSGetEnviron()'s return value to a local variable and then re-binding that is incorrect. We need to directly update what _NSGetEnviron() refers to. --- src/nvim/os/pty_process_unix.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nvim/os/pty_process_unix.c b/src/nvim/os/pty_process_unix.c index 0733589870..348a139e79 100644 --- a/src/nvim/os/pty_process_unix.c +++ b/src/nvim/os/pty_process_unix.c @@ -159,7 +159,7 @@ static void init_child(PtyProcess *ptyproc) FUNC_ATTR_NONNULL_ALL { #if defined(HAVE__NSGETENVIRON) - char **environ = *_NSGetEnviron(); +#define environ (*_NSGetEnviron()) #else extern char **environ; #endif -- cgit From 27a7a4d38405a30611339fc663e426904bda1099 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Sun, 31 Jan 2021 10:43:03 -0500 Subject: Use abort() instead of assert(false) for things that should never happen assert() is compiled out for release builds, but we don't want to continue running in these impossible situations. This also resolves the "implicit fallthrough" warnings for the asserts in switch cases. --- src/nvim/buffer.c | 2 +- src/nvim/charset.c | 4 ++-- src/nvim/eval.c | 2 +- src/nvim/eval/decode.c | 4 ++-- src/nvim/eval/encode.c | 4 ++-- src/nvim/eval/executor.c | 2 +- src/nvim/eval/funcs.c | 4 ++-- src/nvim/eval/typval.c | 10 +++++----- src/nvim/ex_docmd.c | 2 +- src/nvim/ex_getln.c | 2 +- src/nvim/file_search.c | 2 +- src/nvim/lua/converter.c | 6 +++--- src/nvim/ops.c | 4 ++-- src/nvim/os/time.c | 2 +- src/nvim/quickfix.c | 2 +- src/nvim/shada.c | 16 ++++++++-------- src/nvim/tag.c | 2 +- src/nvim/tui/input.c | 2 +- src/nvim/ui_compositor.c | 2 +- src/nvim/viml/parser/expressions.c | 6 +++--- test/symbolic/klee/nvim/charset.c | 4 ++-- test/symbolic/klee/nvim/memory.c | 4 ++-- 22 files changed, 44 insertions(+), 44 deletions(-) diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 0134ee838d..ec39de14f5 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -3270,7 +3270,7 @@ void maketitle(void) case 6: buf_p = strappend(buf_p, " -"); break; case 5: case 7: buf_p = strappend(buf_p, " -+"); break; - default: assert(false); + default: abort(); } if (curbuf->b_fname != NULL) { diff --git a/src/nvim/charset.c b/src/nvim/charset.c index 3e52b3e3ce..be265e3f27 100644 --- a/src/nvim/charset.c +++ b/src/nvim/charset.c @@ -1747,7 +1747,7 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len, goto vim_str2nr_dec; } default: { - assert(false); + abort(); } } } else if ((what & (STR2NR_HEX|STR2NR_OCT|STR2NR_BIN)) @@ -1788,7 +1788,7 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len, } // Do the string-to-numeric conversion "manually" to avoid sscanf quirks. - assert(false); // Should’ve used goto earlier. + abort(); // Should’ve used goto earlier. #define PARSE_NUMBER(base, cond, conv) \ do { \ while (!STRING_ENDED(ptr) && (cond)) { \ diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 8a1556320c..a25b140b2f 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -365,7 +365,7 @@ void eval_init(void) eval_msgpack_type_lists[i] = type_list; if (tv_dict_add(msgpack_types_dict, di) == FAIL) { // There must not be duplicate items in this dictionary by definition. - assert(false); + abort(); } } msgpack_types_dict->dv_lock = VAR_FIXED; diff --git a/src/nvim/eval/decode.c b/src/nvim/eval/decode.c index 638fef331a..bd4dc87d31 100644 --- a/src/nvim/eval/decode.c +++ b/src/nvim/eval/decode.c @@ -147,7 +147,7 @@ static inline int json_decoder_pop(ValuesStackItem obj, tv_clear(&key.val); if (tv_dict_add(last_container.container.vval.v_dict, obj_di) == FAIL) { - assert(false); + abort(); } obj_di->di_tv = obj.val; } else { @@ -480,7 +480,7 @@ static inline int parse_json_string(const char *const buf, const size_t buf_len, break; } default: { - assert(false); + abort(); } } } else { diff --git a/src/nvim/eval/encode.c b/src/nvim/eval/encode.c index 9a9f2e4287..a4d7af7971 100644 --- a/src/nvim/eval/encode.c +++ b/src/nvim/eval/encode.c @@ -174,7 +174,7 @@ static int conv_error(const char *const msg, const MPConvStack *const mpstack, case kMPConvPartial: { switch (v.data.p.stage) { case kMPConvPartialArgs: { - assert(false); + abort(); break; } case kMPConvPartialSelf: { @@ -237,7 +237,7 @@ bool encode_vim_list_to_buf(const list_T *const list, size_t *const ret_len, char *const buf = xmalloc(len); size_t read_bytes; if (encode_read_from_list(&lrstate, buf, len, &read_bytes) != OK) { - assert(false); + abort(); } assert(len == read_bytes); *ret_buf = buf; diff --git a/src/nvim/eval/executor.c b/src/nvim/eval/executor.c index da05ecda43..bbba9d12f2 100644 --- a/src/nvim/eval/executor.c +++ b/src/nvim/eval/executor.c @@ -118,7 +118,7 @@ int eexe_mod_op(typval_T *const tv1, const typval_T *const tv2, return OK; } case VAR_UNKNOWN: { - assert(false); + abort(); } } } diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 7121d413ea..1a7bbf2d0e 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -3307,7 +3307,7 @@ static void f_getcwd(typval_T *argvars, typval_T *rettv, FunPtr fptr) } break; case kCdScopeInvalid: // We should never get here - assert(false); + abort(); } if (from) { @@ -4360,7 +4360,7 @@ static void f_haslocaldir(typval_T *argvars, typval_T *rettv, FunPtr fptr) break; case kCdScopeInvalid: // We should never get here - assert(false); + abort(); } } diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c index 2f8776def4..9be487f4fd 100644 --- a/src/nvim/eval/typval.c +++ b/src/nvim/eval/typval.c @@ -2521,7 +2521,7 @@ void tv_item_lock(typval_T *const tv, const int deep, const bool lock) break; } case VAR_UNKNOWN: { - assert(false); + abort(); } } #undef CHANGE_LOCK @@ -2693,7 +2693,7 @@ bool tv_equal(typval_T *const tv1, typval_T *const tv2, const bool ic, } } - assert(false); + abort(); return false; } @@ -2746,7 +2746,7 @@ bool tv_check_str_or_nr(const typval_T *const tv) return false; } } - assert(false); + abort(); return false; } @@ -2791,7 +2791,7 @@ bool tv_check_num(const typval_T *const tv) return false; } } - assert(false); + abort(); return false; } @@ -2836,7 +2836,7 @@ bool tv_check_str(const typval_T *const tv) return false; } } - assert(false); + abort(); return false; } diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 8b00417ce3..52da7fe4f6 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -7591,7 +7591,7 @@ void post_chdir(CdScope scope, bool trigger_dirchanged) curwin->w_localdir = (char_u *)xstrdup(cwd); break; case kCdScopeInvalid: - assert(false); + abort(); } shorten_fnames(true); diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 8d10e98259..cf6bb6d492 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -6383,7 +6383,7 @@ int hist_type2char(int type) return '>'; } default: { - assert(false); + abort(); } } return NUL; diff --git a/src/nvim/file_search.c b/src/nvim/file_search.c index b1fa0b6779..8beba38509 100644 --- a/src/nvim/file_search.c +++ b/src/nvim/file_search.c @@ -1595,7 +1595,7 @@ void do_autocmd_dirchanged(char *new_dir, CdScope scope, bool changed_window) } case kCdScopeInvalid: { // Should never happen. - assert(false); + abort(); } } diff --git a/src/nvim/lua/converter.c b/src/nvim/lua/converter.c index 030df69caa..83b3729ad3 100644 --- a/src/nvim/lua/converter.c +++ b/src/nvim/lua/converter.c @@ -245,7 +245,7 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv) } else { dictitem_T *const di = tv_dict_item_alloc_len(s, len); if (tv_dict_add(cur.tv->vval.v_dict, di) == FAIL) { - assert(false); + abort(); } kv_push(stack, cur); cur = (TVPopStackItem) { &di->di_tv, false, false, 0 }; @@ -391,7 +391,7 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv) break; } default: { - assert(false); + abort(); } } nlua_pop_typval_table_processing_end: @@ -1200,7 +1200,7 @@ Object nlua_pop_Object(lua_State *const lstate, bool ref, Error *const err) break; } default: { - assert(false); + abort(); } } break; diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 052b07ed44..87d092281a 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -2623,7 +2623,7 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append) } // NOTREACHED case kMTUnknown: - assert(false); + abort(); } } @@ -6092,7 +6092,7 @@ static void set_clipboard(int name, yankreg_T *reg) break; } case kMTUnknown: { - assert(false); + abort(); } } diff --git a/src/nvim/os/time.c b/src/nvim/os/time.c index 4b6533cd0c..5cf628935f 100644 --- a/src/nvim/os/time.c +++ b/src/nvim/os/time.c @@ -97,7 +97,7 @@ void os_microdelay(uint64_t us, bool ignoreinput) const int rv = uv_cond_timedwait(&delay_cond, &delay_mutex, ns_delta); if (0 != rv && UV_ETIMEDOUT != rv) { - assert(false); + abort(); break; } // Else: Timeout proceeded normally. diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index a625c09f78..d24d170a39 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -5648,7 +5648,7 @@ static int get_qfline_items(qfline_T *qfp, list_T *list) == FAIL)) { // tv_dict_add* fail only if key already exist, but this is a newly // allocated dictionary which is thus guaranteed to have no existing keys. - assert(false); + abort(); } return OK; diff --git a/src/nvim/shada.c b/src/nvim/shada.c index 2444910bb3..c0e787380f 100644 --- a/src/nvim/shada.c +++ b/src/nvim/shada.c @@ -765,7 +765,7 @@ static ShaDaReadResult sd_reader_skip(ShaDaReadDef *const sd_reader, (uint64_t) offset); return kSDReadStatusNotShaDa; } - assert(false); + abort(); } return kSDReadStatusSuccess; } @@ -1224,7 +1224,7 @@ static void shada_read(ShaDaReadDef *const sd_reader, const int flags) } case kSDReadStatusFinished: { // Should be handled by the while condition. - assert(false); + abort(); } case kSDReadStatusNotShaDa: case kSDReadStatusReadError: { @@ -1236,7 +1236,7 @@ static void shada_read(ShaDaReadDef *const sd_reader, const int flags) } switch (cur_entry.type) { case kSDItemMissing: { - assert(false); + abort(); } case kSDItemUnknown: { break; @@ -1628,7 +1628,7 @@ static ShaDaWriteResult shada_pack_entry(msgpack_packer *const packer, ((size_t) (!CHECK_DEFAULT(entry, attr))) switch (entry.type) { case kSDItemMissing: { - assert(false); + abort(); } case kSDItemUnknown: { if (spacker->callback(spacker->data, entry.data.unknown_item.contents, @@ -1850,7 +1850,7 @@ static ShaDaWriteResult shada_pack_entry(msgpack_packer *const packer, break; } default: { - assert(false); + abort(); } } } @@ -2147,7 +2147,7 @@ static inline ShaDaWriteResult shada_read_when_writing( } case kSDReadStatusFinished: { // Should be handled by the while condition. - assert(false); + abort(); } case kSDReadStatusNotShaDa: { ret = kSDWriteReadNotShada; @@ -2184,7 +2184,7 @@ static inline ShaDaWriteResult shada_read_when_writing( } case kSDItemHeader: case kSDItemBufferList: { - assert(false); + abort(); } case kSDItemUnknown: { ret = shada_pack_entry(packer, entry, 0); @@ -4044,7 +4044,7 @@ shada_read_next_item_start: } case kSDItemMissing: case kSDItemUnknown: { - assert(false); + abort(); } } entry->type = (ShadaEntryType) type_u64; diff --git a/src/nvim/tag.c b/src/nvim/tag.c index c6b1a0d04c..84ca240734 100644 --- a/src/nvim/tag.c +++ b/src/nvim/tag.c @@ -1461,7 +1461,7 @@ find_tags( p_ic = ignorecase_opt(pat, true, true); break; default: - assert(false); + abort(); } help_save = curbuf->b_help; diff --git a/src/nvim/tui/input.c b/src/nvim/tui/input.c index 124f96e039..3e683a4926 100644 --- a/src/nvim/tui/input.c +++ b/src/nvim/tui/input.c @@ -297,7 +297,7 @@ static void forward_mouse_event(TermInput *input, TermKeyKey *key) len += (size_t)snprintf(buf + len, sizeof(buf) - len, "Release"); break; case TERMKEY_MOUSE_UNKNOWN: - assert(false); + abort(); } len += (size_t)snprintf(buf + len, sizeof(buf) - len, "><%d,%d>", col, row); diff --git a/src/nvim/ui_compositor.c b/src/nvim/ui_compositor.c index 9d3ec21949..06efc9fa99 100644 --- a/src/nvim/ui_compositor.c +++ b/src/nvim/ui_compositor.c @@ -157,7 +157,7 @@ bool ui_comp_put_grid(ScreenGrid *grid, int row, int col, int height, int width, #ifndef NDEBUG for (size_t i = 0; i < kv_size(layers); i++) { if (kv_A(layers, i) == grid) { - assert(false); + abort(); } } #endif diff --git a/src/nvim/viml/parser/expressions.c b/src/nvim/viml/parser/expressions.c index 44b6ab5f5a..e9d82ca87d 100644 --- a/src/nvim/viml/parser/expressions.c +++ b/src/nvim/viml/parser/expressions.c @@ -2078,7 +2078,7 @@ viml_pexpr_parse_process_token: case kExprLexMissing: case kExprLexSpacing: case kExprLexEOC: { - assert(false); + abort(); } case kExprLexInvalid: { ERROR_FROM_TOKEN(cur_token); @@ -3028,7 +3028,7 @@ viml_pexpr_parse_end: // Until trailing "}" it is impossible to distinguish curly braces // identifier and dictionary, so it must not appear in the stack like // this. - assert(false); + abort(); } case kExprNodeInteger: case kExprNodeFloat: @@ -3042,7 +3042,7 @@ viml_pexpr_parse_end: // These are plain values and not containers, for them it should only // be possible to show up in the topmost stack element, but it was // unconditionally popped at the start. - assert(false); + abort(); } case kExprNodeComma: case kExprNodeColon: diff --git a/test/symbolic/klee/nvim/charset.c b/test/symbolic/klee/nvim/charset.c index f9bc3fabc4..fd1c5ee4b9 100644 --- a/test/symbolic/klee/nvim/charset.c +++ b/test/symbolic/klee/nvim/charset.c @@ -62,7 +62,7 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len, goto vim_str2nr_dec; } default: { - assert(false); + abort(); } } } else if ((what & (STR2NR_HEX|STR2NR_OCT|STR2NR_BIN)) @@ -102,7 +102,7 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len, } // Do the string-to-numeric conversion "manually" to avoid sscanf quirks. - assert(false); // Should’ve used goto earlier. + abort(); // Should’ve used goto earlier. #define PARSE_NUMBER(base, cond, conv) \ do { \ while (!STRING_ENDED(ptr) && (cond)) { \ diff --git a/test/symbolic/klee/nvim/memory.c b/test/symbolic/klee/nvim/memory.c index df422cea3e..1614f813d7 100644 --- a/test/symbolic/klee/nvim/memory.c +++ b/test/symbolic/klee/nvim/memory.c @@ -45,7 +45,7 @@ void xfree(void *const p) return; } } - assert(false); + abort(); } void *xrealloc(void *const p, size_t new_size) @@ -63,7 +63,7 @@ void *xrealloc(void *const p, size_t new_size) return ret; } } - assert(false); + abort(); return (void *)(intptr_t)1; } -- cgit From 81794204ce85dd15a62a27275fe717c7033e65d5 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Sun, 31 Jan 2021 10:45:26 -0500 Subject: ci(sr.ht): Use RelWithDebInfo builds Many compiler checks rely on optimizations being enabled, so we want these to show up in CI. Use RelWithDebInfo instead of Release so that assert() statements aren't compiled out. --- .builds/freebsd.yml | 2 +- .builds/openbsd.yml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml index bb7fbeb78b..d5809c42cf 100644 --- a/.builds/freebsd.yml +++ b/.builds/freebsd.yml @@ -28,7 +28,7 @@ tasks: gmake deps - build: | cd neovim - gmake CMAKE_BUILD_TYPE=Release CMAKE_EXTRA_FLAGS="${CMAKE_EXTRA_FLAGS}" nvim + gmake CMAKE_BUILD_TYPE=RelWithDebInfo CMAKE_EXTRA_FLAGS="${CMAKE_EXTRA_FLAGS}" nvim - functionaltest: | cd neovim gmake functionaltest diff --git a/.builds/openbsd.yml b/.builds/openbsd.yml index 2f0f970dcb..0ffc8aa786 100644 --- a/.builds/openbsd.yml +++ b/.builds/openbsd.yml @@ -28,16 +28,16 @@ tasks: mkdir neovim/.deps cd neovim/.deps cmake -G Ninja ../third-party/ - cmake --build . --config Debug + cmake --build . --config RelWithDebInfo - build: | mkdir neovim/build cd neovim/build cmake -G Ninja $CMAKE_EXTRA_FLAGS .. - cmake --build . --config Debug + cmake --build . --config RelWithDebInfo ./bin/nvim --version - functionaltest: | cd neovim/build - cmake --build . --config Debug --target functionaltest + cmake --build . --config RelWithDebInfo --target functionaltest - oldtest: | cd neovim gmake oldtest -- cgit