Jason Franklin wrote:
> My environment is Ubuntu 18.04, GNOME Terminal.
>
> While tinkering around, I discovered that the following snippet of
> Vimscript will result in a segfault:
>
> " This produces a segfault.
> while 1
> silent! let v:errmsg = []
> let v:errmsg = ''
> endwhile
>
> The loop is there because you may have to execute the sequence
> a couple of times before a segfault happens.
>
> Also notice that running:
>
> :let v:errmsg = []
> :echo v:errmsg
>
> does not show the last generated error message as one would expect,
> it shows the empty string.
>
> I wrote a test to prove that my patch sets the error message in
> this case:
>
> func Test_let_errmsg()
> silent! let v:errmsg = []
> call assert_false(empty(v:errmsg))
> endfunc
>
> I'm not exactly sure where to put the test... there were several
> test scripts that seemed relevant here.
>
> I dug into the code and came up with this:
>
> diff --git a/src/eval.c b/src/eval.c
> index d1a7fd37d..c485ecabd 100644
> --- a/src/eval.c
> +++ b/src/eval.c
> @@ -7883,20 +7883,23 @@ set_var(
> || tv_check_lock(v->di_tv.v_lock, name, FALSE))
> return;
>
> - /*
> - * Handle setting internal v: variables separately where needed to
> - * prevent changing the type.
> - */
> + // Handle setting internal v: variables separately where needed to
> + // prevent changing the type.
> if (ht == &vimvarht)
> {
> if (v->di_tv.v_type == VAR_STRING)
> {
> - vim_free(v->di_tv.vval.v_string);
> + VIM_CLEAR(v->di_tv.vval.v_string);
> if (copy || tv->v_type != VAR_STRING)
> - v->di_tv.vval.v_string = vim_strsave(tv_get_string(tv));
> + {
> + if (STRCMP("v:errmsg", name) == 0)
> + tv_get_string(tv); // calls emsg(), which sets v:errmsg
> + else
> + v->di_tv.vval.v_string = vim_strsave(tv_get_string(tv));
> + }
> else
> {
> - /* Take over the string to avoid an extra alloc/free. */
> + // Take over the string to avoid an extra alloc/free.
> v->di_tv.vval.v_string = tv->vval.v_string;
> tv->vval.v_string = NULL;
> }
>
> This patch stops the segfault from happening and lets the check of the "tv"
> variable set v:errmsg (see comment).
>
> I would appreciate some careful review here. I don't precisely understand
> why VIM_CLEAR works instead of vim_free(). I suspect it is due to some check
> for NULL later. Any feedback to help my understanding is always appreciated.
> It may be that a much better solution exists, but I'm not really familiar
> enough with the code to arrive at the perfect fix... though I try.
Good catch! I don't have time to debug right now, but I suspect
tv_get_string() produces an error message and when v_string was not set
to NULL, it gets freed twice.
Solution would be to call vim_strsave() and storing the result in a
local variable, instead of assigning it to v_string. And probably use
tv_get_string_chk() to skip storing the value when there is an error.
--
There is a fine line between courage and foolishness.
Unfortunately, it's not a fence.
/// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net \\\
/// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\ an exciting new programming language -- http://www.Zimbu.org ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///
--
--
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php
---
You received this message because you are subscribed to the Google Groups
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.