Hi

Valgrind memory checker detects that Vim is using freed memory
in the spelling checker code:

==8692== Invalid read of size 1
==8692==    at 0x8199D87: spell_to_word_end (spell.c:15854)
==8692==    by 0x8166424: win_line (screen.c:3054)
==8692==    by 0x8163AD5: win_update (screen.c:1765)
==8692==    by 0x8161C34: update_screen (screen.c:522)
==8692==    by 0x8064F1B: ins_redraw (edit.c:1474)
==8692==    by 0x8063B96: edit (edit.c:688)
==8692==    by 0x812322A: normal_cmd (normal.c:1327)
==8692==    by 0x80E5D2D: main_loop (main.c:1181)
==8692==    by 0x80E587D: main (main.c:940)
==8692==  Address 0x50615F0 is 40 bytes inside a block of size 96 free'd
==8692==    at 0x402237F: free (vg_replace_malloc.c:233)
==8692==    by 0x8113F55: vim_free (misc2.c:1580)
==8692==    by 0x80F864A: ml_flush_line (memline.c:3149)
==8692==    by 0x80F69FE: ml_get_buf (memline.c:2111)
==8692==    by 0x80F68BB: ml_get (memline.c:2034)
==8692==    by 0x818D567: check_need_cap (spell.c:10271)
==8692==    by 0x817C828: spell_move_to (spell.c:2098)
==8692==    by 0x81663D0: win_line (screen.c:3048)
==8692==    by 0x8163AD5: win_update (screen.c:1765)
==8692==    by 0x8161C34: update_screen (screen.c:522)
==8692==    by 0x8064F1B: ins_redraw (edit.c:1474)
==8692==    by 0x8063B96: edit (edit.c:688)
==8692==    by 0x812322A: normal_cmd (normal.c:1327)
==8692==    by 0x80E5D2D: main_loop (main.c:1181)
==8692==    by 0x80E587D: main (main.c:940)

(and then follows several more errors)

Here is the relevant code in screen.c:

  2927     line = ml_get_buf(wp->w_buffer, lnum, FALSE);
  2928     ptr = line;
  ....
  ....
  3037 #ifdef FEAT_SPELL
  3038         /* When spell checking a word we need to figure out the
start of the
  3039          * word and if it's badly spelled or not. */
  3040         if (has_spell)
  3041         {
  3042             int         len;
  3043             hlf_T       spell_hlf = HLF_COUNT;
  3044
  3045             pos = wp->w_cursor;
  3046             wp->w_cursor.lnum = lnum;
  3047             wp->w_cursor.col = (colnr_T)(ptr - line);
!!3048             len = spell_move_to(wp, FORWARD, TRUE, TRUE, &spell_hlf);
  3049             if (len == 0 || (int)wp->w_cursor.col > ptr - line)
  3050             {
  3051                 /* no bad word found at line start, don't check
until end of a
  3052                  * word */
  3053                 spell_hlf = HLF_COUNT;
!!3054                 word_end = (int)(spell_to_word_end(ptr,
wp->w_buffer) - line + 1);
  3055             }

Error happens inside call of spell_to_word_end() at screen.c:3054
because ptr is dereferenced inside spell_to_word_end() but is pointing
to memory which has already been freed (bug!).

ptr was previously freed just a few lines above, as a side effect
of calling spell_move_to(...) 6 lines above at screen.c:3048, because
spell_move_to(...) may in some cases call ml_get(...) which invalidates
previous pointer returned by previous call of ml_get(...).  So call
to spell_move_to invalidates line and ptr which were initialized at
line 2927/2928 in screen.c.

Here is how I can reproduce the bug:

$ valgrind vim -u NONE -c 'set nowrap|set spell|start' -s
spell-access-freed-mem.vim  2> valgrind.log

spell-testcase is a small file generated randomly which triggers this bug:
  http://dominique.pelle.free.fr/spell-access-freed-mem.vim

But happens only if terminal is small enough (80x25 or smaller)

I attach a patch which fixes the bug but please review it.  Maybe there
is a better solution.

I'm using vim-7.1 (Patches 1-242) on Linux x86 in a gnome-terminal, built
with "configure --with-feature=huge", without optimizations (-O0 -g).

-- Dominique

--~--~---------~--~----~------------~-------~--~----~
You received this message from the "vim_dev" maillist.
For more information, visit http://www.vim.org/maillist.php
-~----------~----~----~----~------~----~------~--~---

Index: screen.c
===================================================================
RCS file: /cvsroot/vim/vim7/src/screen.c,v
retrieving revision 1.98
diff -c -r1.98 screen.c
*** screen.c	19 Jan 2008 14:58:17 -0000	1.98
--- screen.c	3 Feb 2008 15:42:20 -0000
***************
*** 2644,2650 ****
  #if defined(FEAT_SIGNS) || (defined(FEAT_QUICKFIX) && defined(FEAT_WINDOWS)) \
  	|| defined(FEAT_SYN_HL) || defined(FEAT_DIFF)
  # define LINE_ATTR
!     int		line_attr = 0;		/* atrribute for the whole line */
  #endif
  #ifdef FEAT_SEARCH_EXTRA
      matchitem_T *cur;			/* points to the match list */
--- 2644,2650 ----
  #if defined(FEAT_SIGNS) || (defined(FEAT_QUICKFIX) && defined(FEAT_WINDOWS)) \
  	|| defined(FEAT_SYN_HL) || defined(FEAT_DIFF)
  # define LINE_ATTR
!     int		line_attr = 0;		/* attribute for the whole line */
  #endif
  #ifdef FEAT_SEARCH_EXTRA
      matchitem_T *cur;			/* points to the match list */
***************
*** 3045,3051 ****
--- 3045,3060 ----
  	    pos = wp->w_cursor;
  	    wp->w_cursor.lnum = lnum;
  	    wp->w_cursor.col = (colnr_T)(ptr - line);
+ 
+ 	    /* Save position in line, since spell_move_to() invalidates
+ 	     * line and ptr as it may call ml_get() */
+ 	    v = (long)(ptr - line);
  	    len = spell_move_to(wp, FORWARD, TRUE, TRUE, &spell_hlf);
+ 
+ 	    /* Get line again and restore ptr */
+ 	    line = ml_get_buf(wp->w_buffer, lnum, FALSE);
+ 	    ptr = line + v;
+ 
  	    if (len == 0 || (int)wp->w_cursor.col > ptr - line)
  	    {
  		/* no bad word found at line start, don't check until end of a

Raspunde prin e-mail lui