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 ==
¤t_funccal->l_vars.dv_hashtab)
3744| d = ¤t_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 == ¤t_funccal->l_vars.dv_hashtab)
- d = ¤t_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 == ¤t_funccal->l_vars.dv_hashtab)
+ d = ¤t_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;