Valgrind memory checker finds a bug in vim (when running
test case vim7/src/testdir/test49.vim).
Test 49 spawns several vim processes. Bug happens in
some of the vim processes spawned by the main test49.vim
script.
Here is the bug reported by valgrind:
==4470== Invalid read of size 1
==4470== at 0x80D83D7: msg_outtrans_attr (message.c:1266)
==4470== by 0x80D83B9: msg_outtrans (message.c:1258)
==4470== by 0x807C681: list_one_var_a (eval.c:18044)
==4470== by 0x807C59E: list_one_var (eval.c:18008)
==4470== by 0x80669C6: list_hashtable_vars (eval.c:1953)
==4470== by 0x8066B05: list_vim_vars (eval.c:2007)
==4470== by 0x8066452: ex_let (eval.c:1730)
==4470== by 0x8092D64: do_one_cmd (ex_docmd.c:2622)
==4470== by 0x809070D: do_cmdline (ex_docmd.c:1100)
==4470== by 0x808FE72: do_cmdline_cmd (ex_docmd.c:706)
==4470== by 0x80C6852: exe_commands (main.c:2638)
==4470== by 0x80C4816: main (main.c:874)
==4470== Address 0x4206FE8 is 0 bytes inside a block of size 3 free'd
==4470== at 0x402123A: free (vg_replace_malloc.c:233)
==4470== by 0x80EA35D: vim_free (misc2.c:1560)
==4470== by 0x807B4D1: set_vim_var_string (eval.c:17197)
==4470== by 0x80D6EEA: msg_attr_keep (message.c:144)
==4470== by 0x80D6EB9: msg_attr (message.c:129)
==4470== by 0x807C5D5: list_one_var_a (eval.c:18020)
==4470== by 0x807C59E: list_one_var (eval.c:18008)
==4470== by 0x80669C6: list_hashtable_vars (eval.c:1953)
==4470== by 0x8066B05: list_vim_vars (eval.c:2007)
==4470== by 0x8066452: ex_let (eval.c:1730)
==4470== by 0x8092D64: do_one_cmd (ex_docmd.c:2622)
==4470== by 0x809070D: do_cmdline (ex_docmd.c:1100)
=4470==
==4470== Invalid read of size 1
==4470== at 0x80D84A1: msg_outtrans_len_attr (message.c:1365)
==4470== by 0x80D83F7: msg_outtrans_attr (message.c:1266)
==4470== by 0x80D83B9: msg_outtrans (message.c:1258)
==4470== by 0x807C681: list_one_var_a (eval.c:18044)
==4470== by 0x807C59E: list_one_var (eval.c:18008)
==4470== by 0x80669C6: list_hashtable_vars (eval.c:1953)
==4470== by 0x8066B05: list_vim_vars (eval.c:2007)
==4470== by 0x8066452: ex_let (eval.c:1730)
==4470== by 0x8092D64: do_one_cmd (ex_docmd.c:2622)
==4470== by 0x809070D: do_cmdline (ex_docmd.c:1100)
==4470== by 0x808FE72: do_cmdline_cmd (ex_docmd.c:706)
==4470== by 0x80C6852: exe_commands (main.c:2638)
==4470== Address 0x4206FE8 is 0 bytes inside a block of size 3 free'd
==4470== at 0x402123A: free (vg_replace_malloc.c:233)
==4470== by 0x80EA35D: vim_free (misc2.c:1560)
==4470== by 0x807B4D1: set_vim_var_string (eval.c:17197)
==4470== by 0x80D6EEA: msg_attr_keep (message.c:144)
==4470== by 0x80D6EB9: msg_attr (message.c:129)
==4470== by 0x807C5D5: list_one_var_a (eval.c:18020)
==4470== by 0x807C59E: list_one_var (eval.c:18008)
==4470== by 0x80669C6: list_hashtable_vars (eval.c:1953)
==4470== by 0x8066B05: list_vim_vars (eval.c:2007)
==4470== by 0x8066452: ex_let (eval.c:1730)
==4470== by 0x8092D64: do_one_cmd (ex_docmd.c:2622)
==4470== by 0x809070D: do_cmdline (ex_docmd.c:1100)
==4470==
etc, etc...
Here is some of the relevant code (eval.c)
18013 static void
18014 list_one_var_a(prefix, name, type, string)
18015 char_u *prefix;
18016 char_u *name;
18017 int type;
18018 char_u *string;
18019 {
FREE!!! 18020 msg_attr(prefix, 0); /* don't use msg(), it
overwrites "v:statusmsg" */
18021 if (name != NULL) /* "a:" vars don't have a name stored */
18022 msg_puts(name);
18023 msg_putchar(' ');
18024 msg_advance(22);
18025 if (type == VAR_NUMBER)
18026 msg_putchar('#');
18027 else if (type == VAR_FUNC)
18028 msg_putchar('*');
18029 else if (type == VAR_LIST)
18030 {
18031 msg_putchar('[');
18032 if (*string == '[')
18033 ++string;
18034 }
18035 else if (type == VAR_DICT)
18036 {
18037 msg_putchar('{');
18038 if (*string == '{')
18039 ++string;
18040 }
18041 else
18042 msg_putchar(' ');
18043
USE!!! 18044 msg_outtrans(string);
18045
18046 if (type == VAR_FUNC)
18047 msg_puts((char_u *)"()");
18048 }
In a nuttshell: line eval.c:18020 frees some memory which is later
used at line eval.c:18044.
I put a couple of printf in code to convince myself that valgrind's
message is not spurious.
In some cases, when entering above function list_one_var_a()
'string' pointer passed as argument points to vimvars[idx].vv_str
(idx being VV_STATUSMSG). vimvars[idx].vv_str gets freed at line
18020 and string gets used again at line 18044 (hence bug).
The following traces describe in more details the chronology
of events when:
- 'vimvars[idx].vv_str' gets dynamically allocated
- 'string' pointer gets assigned to 'vimvars[idx].vv_str' (aliasing)
- 'vimvars[idx].vv_str' pointer is freed
- 'string' is used (bug)
It involves 3 successive calls to list_one_var() within
one call of list_hash_table_vars() as follows:
eval.c:2007 list_hash_table_vars()
eval.c:1953 | list_one_var()
eval.c:18008 | | list_one_var_a()
eval.c:18020 | | | msg_attr()
message.c:129 | | | | msg_attr_keep()
message.c:144 | | | | | set_vim_var_string() ---> Variable
vimvars[idx].vv_str gets...
eval.c:17201 | | | | | | vim_strsave()
misc2.c:1142 | | | | | | | alloc() -----------> ... allocated here.
|
eval.c:1953 | list_one_var() -----------------> Another call to list_one_var()
eval.c:18007 | | echo_string() ---------------> 'string' pointer
gets assigned ...
eval.c:6873 | | | get_tv_string_buf()
eval.c:17693 | | | | get_tv_string_buf_chk() --> ... to
vimvars[idx].vv_str (aliasing)
| | at line eval.c:17728
eval.c:1953 | list_one_var() -----------------> Another call to list_one_var()
eval.c:18008 | | list_one_var_a()
eval.c:18020 | | | msg_attr()
message.c:129 | | | | msg_attr_keep()
message.c:144 | | | | | set_vim_var_string()
eval.c:17197 | | | | | | vim_free() -----------> Free vimvars[idx].vv_str here
eval.c:18044 | | | msg_outtrans(string) -------> Use 'string' pointer
here (which is
| equal to vimvars[idx].vv_str
| hence pointing to
freed memory
| ***BUG***
It probably works by chance since memory is used shortly
after being freed, so it's not overwritten yet.
I have not found how to fix it yet.
Here is how I can reproduce bug (100% of the time) with valgrind:
1/ Create wrapper script to run vim in valgrind:
$ cat vim7/src/vim-valgrind.sh
#!/bin/sh
valgrind YOUR_VIM_DIR/vim7/src/vim $* 2> /tmp/vg.$$
$ chmod a+x YOUR_VIM_DIR/vim7/src/vim-valgrind.sh
2/ Change line 459 in src/testdir/test49.vim to call vim-valgrind.sh:
[EMAIL PROTECTED]:~/sb/vim7/src/testdir$ cvs diff test49.vim
Index: test49.vim
===================================================================
RCS file: /cvsroot/vim/vim7/src/testdir/test49.vim,v
retrieving revision 1.12
diff -r1.12 test49.vim
459c459
< exec "!echo '" . debug_quits . "q' | ../vim -u NONE -N -Xes"
. redirect .
---
> exec "!echo '" . debug_quits . "q' | ../vim-valgrind.sh -u
NONE -N -Xes" . redirect .
3/ Run test49
$ cd vim7/testdir
$ make test49.out
4/ Look at /tmp/vg.* files for valgrind errors
I am using vim-7.1 (patches: 1-59) on Linux x86, built without optimisations.
VIM - Vi IMproved 7.1 (2007 May 12, compiled Aug 11 2007 17:42:05)
Included patches: 1-59
Compiled by [EMAIL PROTECTED]
Normal version without GUI. Features included (+) or not (-):
-arabic +autocmd -balloon_eval -browse +builtin_terms +byte_offset +cindent
-clientserver -clipboard +cmdline_compl +cmdline_hist +cmdline_info +comments
+cryptv -cscope +cursorshape +dialog_con +diff +digraphs -dnd -ebcdic
-emacs_tags +eval +ex_extra +extra_search -farsi +file_in_path +find_in_path
+folding -footer +fork() -gettext -hangul_input -iconv +insert_expand +jumplist
-keymap -langmap +libcall +linebreak +lispindent +listcmds +localmap +menu
+mksession +modify_fname +mouse -mouseshape -mouse_dec -mouse_gpm
-mouse_jsbterm -mouse_netterm +mouse_xterm -multi_byte +multi_lang -mzscheme
-netbeans_intg -osfiletype +path_extra -perl +postscript +printer -profile
-python +quickfix +reltime -rightleft -ruby +scrollbind -signs +smartindent
-sniff +statusline -sun_workshop +syntax +tag_binary +tag_old_static
-tag_any_white -tcl +terminfo +termresponse +textobjects +title -toolbar
+user_commands +vertsplit +virtualedit +visual +visualextra +viminfo +vreplace
+wildignore +wildmenu +windows +writebackup -X11 -xfontset -xim -xsmp
-xterm_clipboard -xterm_save
system vimrc file: "$VIM/vimrc"
user vimrc file: "$HOME/.vimrc"
user exrc file: "$HOME/.exrc"
fall-back for $VIM: "/usr/local/share/vim"
Compilation: gcc -c -I. -Iproto -DHAVE_CONFIG_H -O0 -g -Wall
Linking: gcc -L/usr/local/lib -o vim -lncurses
-- Dominique
--~--~---------~--~----~------------~-------~--~----~
You received this message from the "vim_dev" maillist.
For more information, visit http://www.vim.org/maillist.php
-~----------~----~----~----~------~----~------~--~---