Hi

Vim-7.4.1046 (and older) segfaults on Linux x86_64 when doing:

$ vim -u NONE -c 'unlet! c count'
Vim: Caught deadly signal SEGV
Vim: Finished.
Segmentation fault (core dumped)

Interestingly, vim-7.4.52 (that comes with Ubuntu-14.04)
does not crash.  I did not have the time to do a bisection to
see which patch introduced the bug.

Valgrind shows:

==11067== Memcheck, a memory error detector
==11067== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==11067== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==11067== Command: ./vim -u NONE -c unlet!\ c\ count
==11067== Parent PID: 22405
==11067==
==11067== Invalid read of size 8
==11067==    at 0x43879F: do_unlet (eval.c:3748)
==11067==    by 0x444B37: do_unlet_var (eval.c:3676)
==11067==    by 0x444B37: ex_unletlock (eval.c:3639)
==11067==    by 0x4661E2: do_one_cmd (ex_docmd.c:2962)
==11067==    by 0x4661E2: do_cmdline (ex_docmd.c:1133)
==11067==    by 0x408F90: exe_commands (main.c:2928)
==11067==    by 0x408F90: main (main.c:962)
==11067==  Address 0x8 is not stack'd, malloc'd or (recently) free'd
==11067==

gdb shows that a NULL pointer is dereferenced at src/eval.c:3748:

 3726|     int
 3727| do_unlet(name, forceit)
 3728|     char_u      *name;
 3729|     int         forceit;
 3730| {
 3731|     hashtab_T   *ht;
 3732|     hashitem_T  *hi;
 3733|     char_u      *varname;
 3734|     dict_T      *d;
 3735|     dictitem_T  *di;
 3736|
 3737|     ht = find_var_ht(name, &varname);
 3738|     if (ht != NULL && *varname != NUL)
 3739|     {
 3740|         if (ht == &globvarht)
 3741|             d = &globvardict;
 3742|         else if (current_funccal != NULL
 3743|                                  && ht ==
&current_funccal->l_vars.dv_hashtab)
 3744|             d = &current_funccal->l_vars;
 3745|         else
 3746|         {
 3747|             di = find_var_in_ht(ht, *name, (char_u *)"", FALSE);
 3748|>            d = di->di_tv.vval.v_dict;
 3749|         }

(gdb) p di
$1 = (dictitem_T *) 0x0

(gdb) p name
$2 = (char_u *) 0x81ecf9 "count"

Attached patch fixes the bug.  All tests pass, but I don't know this
code enough to tell whether it's entirely correct.

Bug was found by fuzzing, using afl-fuzz. I still need to describe how
to use afl-fuzz with vim when I find time by the way.

Regards
Dominique

-- 
-- 
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.
diff --git a/src/eval.c b/src/eval.c
index feaa71c..6799871 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -3737,23 +3737,24 @@ do_unlet(name, forceit)
     ht = find_var_ht(name, &varname);
     if (ht != NULL && *varname != NUL)
     {
-	if (ht == &globvarht)
-	    d = &globvardict;
-	else if (current_funccal != NULL
-				 && ht == &current_funccal->l_vars.dv_hashtab)
-	    d = &current_funccal->l_vars;
-	else
-	{
-	    di = find_var_in_ht(ht, *name, (char_u *)"", FALSE);
-	    d = di->di_tv.vval.v_dict;
-	}
 	hi = hash_find(ht, varname);
 	if (!HASHITEM_EMPTY(hi))
 	{
 	    di = HI2DI(hi);
 	    if (var_check_fixed(di->di_flags, name, FALSE)
-		    || var_check_ro(di->di_flags, name, FALSE)
-		    || tv_check_lock(d->dv_lock, name, FALSE))
+		    || var_check_ro(di->di_flags, name, FALSE))
+		return NULL;
+	    if (ht == &globvarht)
+		d = &globvardict;
+	    else if (current_funccal != NULL
+				     && ht == &current_funccal->l_vars.dv_hashtab)
+		d = &current_funccal->l_vars;
+	    else
+	    {
+		di = find_var_in_ht(ht, *name, (char_u *)"", FALSE);
+		d = (di == NULL) ? NULL : di->di_tv.vval.v_dict;
+	    }
+	    if (d == NULL || tv_check_lock(d->dv_lock, name, FALSE))
 		return FAIL;
 	    delete_var(ht, hi);
 	    return OK;

Raspunde prin e-mail lui