Ingo Karkat wrote:

>
> Hello VIM developers,
>
> I've encountered occasional endless loops when trying to jump to the next
> misspelled word (via ]s) in HTML documents, in the case when there aren't any
> misspellings. VIM then starts consuming all available CPU until the operation 
> is
> aborted via CTRL-C. I was able to come up with a minimal test case to 
> reproduce
> this problem:
>
> cat > test.html <<'EOF'
> <html>
>        <body>
>                <p> In here appears the bug. </p>
>        </body>
> </html>
> EOF
> vim -N -u NONE test.html
> :syntax on
> :setlocal spell
> /here
> :normal! ]s
> " VIM hangs; press CTRL-C to get out of the loop.
> :normal! j]s
> " On any other line, VIM just correctly prints
> " "search hit BOTTOM, continuing at TOP"
>
> The loop only occurs when the cursor is inside the <p>...</p>. It seems that 
> VIM
> then doesn't detect that the entire buffer has been searched and keeps on
> searching forever; the bug doesn't manifest itself when 'wrapscan' is turned 
> off.
> The syntax/html.vim script sets ':syn spell toplevel' and attaches @Spell to
> some syntax clusters, but doesn't do anything strange or overly complex.
> Probably, other filetypes can be affected by this, too.
>
> I can reproduce this problem starting from VIM 7.0 up to VIM 7.2.84, on MS
> Windows and Linux/x86.
>
> -- regards, ingo


Confirmed here.  I can also reproduce it with vim-7.2.88 on Linux x86
and gvim (GTK2 GUI).

Attached patch fixes it, but please review it.

When pressing ]s, I see "search hit BOTTOM, continuing at TOP"
and CPU usage climbs to 100%.  In the terminal, I see the cursor
at the end of "search hit BOTTOM, continuing at TOP" which is quickly
flickering, so message"search hit BOTTOM, continuing at TOP" is
probably being redisplayed many times in a loop.

Attaching with gdb, I sample a couple of stack traces when pressing
CTRL-C:

(gdb) bt
#0  0x0819bcca in syn_current_attr (syncing=0, displaying=1,
can_spell=0xbfa3cb4c, keep_state=0)
    at syntax.c:1975
#1  0x0819b7e2 in get_syntax_attr (col=16, can_spell=0xbfa3cb4c,
keep_state=0) at syntax.c:1771
#2  0x081a30ca in syn_get_id (wp=0x8e08374, lnum=3, col=16, trans=0,
spellp=0xbfa3cb4c, keep_state=0)
    at syntax.c:6134
#3  0x0817c8f8 in spell_move_to (wp=0x8e08374, dir=1, allwords=1,
curline=0, attrp=0x0) at spell.c:2284
#4  0x0812c01d in nv_brackets (cap=0xbfa3cca4) at normal.c:6563
#5  0x081231ed in normal_cmd (oap=0xbfa3cd50, toplevel=1) at normal.c:1200
#6  0x080e60ae in main_loop (cmdwin=0, noexmode=0) at main.c:1180
#7  0x080e5bfb in main (argc=5, argv=0xbfa3cf54) at main.c:939


(gdb) bt
#0  0x081a2c71 in in_id_list (cur_si=0x8e1e454, list=0x8e0e3a0,
ssp=0x8ec1958, contained=1)
    at syntax.c:5927
#1  0x0819bd5a in syn_current_attr (syncing=0, displaying=1,
can_spell=0xbfa3cb4c, keep_state=0)
    at syntax.c:1975
#2  0x0819b7e2 in get_syntax_attr (col=46, can_spell=0xbfa3cb4c,
keep_state=0) at syntax.c:1771
#3  0x081a30ca in syn_get_id (wp=0x8e08374, lnum=3, col=46, trans=0,
spellp=0xbfa3cb4c, keep_state=0)
    at syntax.c:6134
#4  0x0817c8f8 in spell_move_to (wp=0x8e08374, dir=1, allwords=1,
curline=0, attrp=0x0) at spell.c:2284
#5  0x0812c01d in nv_brackets (cap=0xbfa3cca4) at normal.c:6563
#6  0x081231ed in normal_cmd (oap=0xbfa3cd50, toplevel=1) at normal.c:1200
#7  0x080e60ae in main_loop (cmdwin=0, noexmode=0) at main.c:1180
#8  0x080e5bfb in main (argc=5, argv=0xbfa3cf54) at main.c:939

If I put a debug fprintf(stderr, ...) before call to
spell_move_to(...) @ normal.c:6563
I see that the message printed only once.  So spell_move_to() does not return.

I I put a debug fprintf(stderr, ...) before call to give_warning(...)
@ spell.c:2374
I see the message printed many times in a loop so give_warning(...) returns.

Vim is thus looping inside spell_move_to(...), calling
give_warning(...) multiple
times.  This is inside the "while (!got_int)" loop at spell.c:2209.

If I put a printf(stderr, ...) inside this while loop before this line
in spell.c:

2211   line = ml_get_buf(wp->w_buffer, lnum, FALSE);

... then I see that ml_get_buf(...) is called for lines:
3, 4, 5, 1 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2...

I see that we don't check for wrapping when looping forward, but
we do check for wrapping when looping backward.

Attached patch fixes it but please review it.

Regards

-- 
Dominique http://dominiko.livejournal.com

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

Index: spell.c
===================================================================
RCS file: /cvsroot/vim/vim7/src/spell.c,v
retrieving revision 1.121
diff -c -r1.121 spell.c
*** spell.c	9 Dec 2008 21:34:19 -0000	1.121
--- spell.c	25 Jan 2009 20:34:24 -0000
***************
*** 2335,2348 ****
  	if (curline)
  	    break;	/* only check cursor line */
  
  	/* Advance to next line. */
  	if (dir == BACKWARD)
  	{
- 	    /* If we are back at the starting line and searched it again there
- 	     * is no match, give up. */
- 	    if (lnum == wp->w_cursor.lnum && wrapped)
- 		break;
- 
  	    if (lnum > 1)
  		--lnum;
  	    else if (!p_ws)
--- 2335,2348 ----
  	if (curline)
  	    break;	/* only check cursor line */
  
+ 	/* If we are back at the starting line and searched it again there
+ 	    * is no match, give up. */
+ 	if (lnum == wp->w_cursor.lnum && wrapped)
+ 	    break;
+ 
  	/* Advance to next line. */
  	if (dir == BACKWARD)
  	{
  	    if (lnum > 1)
  		--lnum;
  	    else if (!p_ws)

Raspunde prin e-mail lui