There is a possibility of Vim crashing when a variable or an option
('omnifunc' or 'completefunc') is unset or has its value modified.

The crash is due to an invalid memory access, which is reported by
Valgrind as follows:

#v+
==19657== Invalid write of size 1
==19657==    at 0x8077102: call_func (eval.c:8208)
==19657==    by 0x8076BA9: get_func_tv (eval.c:7976)
==19657==    by 0x8073188: eval7 (eval.c:5023)
==19657==    by 0x8072AA1: eval6 (eval.c:4690)
==19657==    by 0x8072697: eval5 (eval.c:4506)
==19657==    by 0x8071C41: eval4 (eval.c:4201)
==19657==    by 0x8071AAF: eval3 (eval.c:4113)
==19657==    by 0x8071951: eval2 (eval.c:4042)
==19657==    by 0x80717A2: eval1 (eval.c:3967)
==19657==    by 0x8086DD6: ex_echo (eval.c:19459)
==19657==    by 0x80A1150: do_one_cmd (ex_docmd.c:2629)
==19657==    by 0x809EA29: do_cmdline (ex_docmd.c:1098)
==19657==    by 0x809CCD4: do_source (ex_cmds2.c:3204)
==19657==    by 0x809C4FF: cmd_source (ex_cmds2.c:2809)
==19657==    by 0x809C457: ex_source (ex_cmds2.c:2782)
==19657==    by 0x80A1150: do_one_cmd (ex_docmd.c:2629)
==19657==    by 0x809EA29: do_cmdline (ex_docmd.c:1098)
==19657==    by 0x809E0E3: do_cmdline_cmd (ex_docmd.c:704)
==19657==    by 0x80E2572: exe_commands (main.c:2733)
==19657==    by 0x80DFF26: main (main.c:888)
==19657==  Address 0x4e17343 is 11 bytes inside a block of size 12 free'd
==19657==    at 0x4023836: free (vg_replace_malloc.c:325)
==19657==    by 0x810E0EC: vim_free (misc2.c:1647)
==19657==    by 0x80858FA: clear_tv (eval.c:18562)
==19657==    by 0x80862A8: delete_var (eval.c:19029)
==19657==    by 0x8070E6A: do_unlet (eval.c:3555)
==19657==    by 0x8070CB8: do_unlet_var (eval.c:3499)
==19657==    by 0x8070BC3: ex_unletlock (eval.c:3462)
==19657==    by 0x8070A22: ex_unlet (eval.c:3400)
==19657==    by 0x80A1150: do_one_cmd (ex_docmd.c:2629)
==19657==    by 0x809EA29: do_cmdline (ex_docmd.c:1098)
==19657==    by 0x808ABDC: call_user_func (eval.c:21332)
==19657==    by 0x8076F55: call_func (eval.c:8130)
==19657==    by 0x8076BA9: get_func_tv (eval.c:7976)
==19657==    by 0x8073188: eval7 (eval.c:5023)
==19657==    by 0x8072AA1: eval6 (eval.c:4690)
==19657==    by 0x8072697: eval5 (eval.c:4506)
==19657==    by 0x8071C41: eval4 (eval.c:4201)
==19657==    by 0x8071AAF: eval3 (eval.c:4113)
==19657==    by 0x8071951: eval2 (eval.c:4042)
==19657==    by 0x80717A2: eval1 (eval.c:3967)
==19657==    by 0x8086DD6: ex_echo (eval.c:19459)
==19657==    by 0x80A1150: do_one_cmd (ex_docmd.c:2629)
==19657==    by 0x809EA29: do_cmdline (ex_docmd.c:1098)
==19657==    by 0x809CCD4: do_source (ex_cmds2.c:3204)
==19657==    by 0x809C4FF: cmd_source (ex_cmds2.c:2809)
==19657==    by 0x809C457: ex_source (ex_cmds2.c:2782)
==19657==    by 0x80A1150: do_one_cmd (ex_docmd.c:2629)
==19657==    by 0x809EA29: do_cmdline (ex_docmd.c:1098)
==19657==    by 0x809E0E3: do_cmdline_cmd (ex_docmd.c:704)
==19657==    by 0x80E2572: exe_commands (main.c:2733)
==19657==    by 0x80DFF26: main (main.c:888)
#v-

The invalid memory access can be triggered by executing the following
script:
#v+
func FuncWithRef(a)
  unlet g:FuncRef
  return a:a
endfunc
let g:FuncRef=function("FuncWithRef")
echo g:FuncRef(333)
q
#v-

The attached patch fixes the problem and modifies test 34 to cause the
freed memory.

-- 
Cheers,
Lech

-- 
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
diff --git a/src/eval.c b/src/eval.c
index be59f98..caa3224 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -8023,26 +8023,36 @@ call_func(name, len, rettv, argcount, argvars, firstline, lastline,
     int		i;
     int		llen;
     ufunc_T	*fp;
-    int		cc;
 #define FLEN_FIXED 40
     char_u	fname_buf[FLEN_FIXED + 1];
     char_u	*fname;
+    char_u      *name_save;
+
+    /* NOTE that if "name" comes from a funcref variable, while evaluating the
+     * function it is possible that the memory pointed to by "name" will be
+     * freed as a result of executing e.g.
+     * unlet FuncRefVariable
+     * Let's make a copy of "name" to be able to modify the string to heart's
+     * content without having to restore it afterwards.
+     */
+    name_save = vim_strsave(name);
+    if (name_save == NULL)
+	return FAIL;
 
     /*
      * In a script change <SID>name() and s:name() to K_SNR 123_name().
      * Change <SNR>123_name() to K_SNR 123_name().
      * Use fname_buf[] when it fits, otherwise allocate memory (slow).
      */
-    cc = name[len];
-    name[len] = NUL;
-    llen = eval_fname_script(name);
+    name_save[len] = NUL;
+    llen = eval_fname_script(name_save);
     if (llen > 0)
     {
 	fname_buf[0] = K_SPECIAL;
 	fname_buf[1] = KS_EXTRA;
 	fname_buf[2] = (int)KE_SNR;
 	i = 3;
-	if (eval_fname_sid(name))	/* "<SID>" or "s:" */
+	if (eval_fname_sid(name_save))	/* "<SID>" or "s:" */
 	{
 	    if (current_SID <= 0)
 		error = ERROR_SCRIPT;
@@ -8052,25 +8062,25 @@ call_func(name, len, rettv, argcount, argvars, firstline, lastline,
 		i = (int)STRLEN(fname_buf);
 	    }
 	}
-	if (i + STRLEN(name + llen) < FLEN_FIXED)
+	if (i + STRLEN(name_save + llen) < FLEN_FIXED)
 	{
-	    STRCPY(fname_buf + i, name + llen);
+	    STRCPY(fname_buf + i, name_save + llen);
 	    fname = fname_buf;
 	}
 	else
 	{
-	    fname = alloc((unsigned)(i + STRLEN(name + llen) + 1));
+	    fname = alloc((unsigned)(i + STRLEN(name_save + llen) + 1));
 	    if (fname == NULL)
 		error = ERROR_OTHER;
 	    else
 	    {
 		mch_memmove(fname, fname_buf, (size_t)i);
-		STRCPY(fname + i, name + llen);
+		STRCPY(fname + i, name_save + llen);
 	    }
 	}
     }
     else
-	fname = name;
+	fname = name_save;
 
     *doesrange = FALSE;
 
@@ -8185,29 +8195,29 @@ call_func(name, len, rettv, argcount, argvars, firstline, lastline,
 	switch (error)
 	{
 	    case ERROR_UNKNOWN:
-		    emsg_funcname(N_("E117: Unknown function: %s"), name);
+		    emsg_funcname(N_("E117: Unknown function: %s"), name_save);
 		    break;
 	    case ERROR_TOOMANY:
-		    emsg_funcname(e_toomanyarg, name);
+		    emsg_funcname(e_toomanyarg, name_save);
 		    break;
 	    case ERROR_TOOFEW:
 		    emsg_funcname(N_("E119: Not enough arguments for function: %s"),
-									name);
+									name_save);
 		    break;
 	    case ERROR_SCRIPT:
 		    emsg_funcname(N_("E120: Using <SID> not in a script context: %s"),
-									name);
+									name_save);
 		    break;
 	    case ERROR_DICT:
 		    emsg_funcname(N_("E725: Calling dict function without Dictionary: %s"),
-									name);
+									name_save);
 		    break;
 	}
     }
 
-    name[len] = cc;
-    if (fname != name && fname != fname_buf)
+    if (fname != name_save && fname != fname_buf)
 	vim_free(fname);
+    vim_free(name_save);
 
     return ret;
 }
diff --git a/src/testdir/test34.in b/src/testdir/test34.in
index 5eef715..28fd00c 100644
--- a/src/testdir/test34.in
+++ b/src/testdir/test34.in
@@ -35,6 +35,11 @@ STARTTEST
 :  let g:counter = 0
 :  return ''
 :endfunc
+:func FuncWithRef(a)
+:  unlet g:FuncRef
+:  return a:a
+:endfunc
+:let g:FuncRef=function("FuncWithRef")
 :let counter = 0
 :inoremap <expr> ( ListItem()
 :inoremap <expr> [ ListReset()
@@ -47,6 +52,7 @@ C=Table("xxx", 4, "asdf")
  =retval
  =Compute(45, 5, "retval")
  =retval
+ =g:FuncRef(333)
 
 XX+-XX
 ---*---
diff --git a/src/testdir/test34.ok b/src/testdir/test34.ok
index 368ae10..951dd8b 100644
--- a/src/testdir/test34.ok
+++ b/src/testdir/test34.ok
@@ -1,4 +1,4 @@
-xxx4asdf fail nop ok 9
+xxx4asdf fail nop ok 9 333
 XX111XX
 ---222---
 1. one

Raspunde prin e-mail lui