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
-~----------~----~----~----~------~----~------~--~---

Raspunde prin e-mail lui