It does not happens all the time and it's quite rare. I don't have
a reproducible test case, which makes it hard to debug. It just
happened today using Vim-7.2.163 (in xterm on Linux x86_64).
I attached to the runaway process with cgcb and I can see where
it's looping forever:
edit.c:
6433│ for (;;)
6434│ {
6435├> if (gchar_cursor() == NUL && curwin->w_cursor.col > 0)
6436│ --curwin->w_cursor.col;
6437│ cc = gchar_cursor();
6438│ if (!vim_iswhite(cc))
6439│ break;
6440│ (void)del_char(TRUE);
6441│ }
Stepping over line by line with gdb, the following lines in edit.c
are being executed indefinitely:
6435, 6437, 6438, 6440 and then back to
6435, 6437, 6438, 6440, etc.
While looping, I see that 'curwin->w_cursor' and 'cc' always remained
identical:
(gdb) p curwin->w_cursor
$11 = {
lnum = 133,
col = 2,
coladd = 0
}
(gdb) p cc
$12 = 32
The file I was editing has 1487 lines. Line 133 is an empty line.
So the column of the cursor (2) looks wrong I think.
When stepping into del_char(TRUE) at line 6440, I see that del_bytes()
always returns FAIL at misc1.c:2213:
#0 del_bytes (count=1, fixpos_arg=1, use_delcombine=1) at misc1.c:2213
#1 0x00000000004cd622 in del_chars (count=1, fixpos=1) at misc1.c:2180
#2 0x00000000004cd58c in del_char (fixpos=1) at misc1.c:2153
#3 0x000000000042a7c9 in stop_insert (end_insert_pos=0x83b870, esc=1)
at edit.c:6440
#4 0x000000000042c968 in ins_esc (count=0x7fff8c049c68, cmdchar=65,
nomove=0) at edit.c:7954
#5 0x0000000000421a86 in edit (cmdchar=65, startln=0, count=-1) at edit.c:927
#6 0x00000000004f66f4 in invoke_edit (cap=0x7fff8c049db0, repl=0,
cmd=65, startln=0) at normal.c:8888
#7 0x00000000004f6691 in nv_edit (cap=0x7fff8c049db0) at normal.c:8861
#8 0x00000000004e946d in normal_cmd (oap=0x7fff8c049e80, toplevel=1)
at normal.c:1189
#9 0x00000000004a90a2 in main_loop (cmdwin=0, noexmode=0) at main.c:1180
#10 0x00000000004a8be8 in main (argc=2, argv=0x7fff8c04a178) at main.c:939
2193│ del_bytes(count, fixpos_arg, use_delcombine)
2194│ long count;
2195│ int fixpos_arg;
2196│ int use_delcombine; /* 'delcombine' option applies */
2197│ {
2198│ char_u *oldp, *newp;
2199│ colnr_T oldlen;
2200│ linenr_T lnum = curwin->w_cursor.lnum;
2201│ colnr_T col = curwin->w_cursor.col;
2202│ int was_alloced;
2203│ long movelen;
2204│ int fixpos = fixpos_arg;
2205│
2206│ oldp = ml_get(lnum);
2207│ oldlen = (int)STRLEN(oldp);
2208│
2209│ /*
2210│ * Can't do anything when the cursor is on the NUL after the line.
2211│ */
2212│ if (col >= oldlen)
2213├> return FAIL;
(gdb) p col
$34 = 2
(gdb) p oldlen
$35 = 0
(gdb) p oldp
$36 = (char_u *) 0x8f59a7 ""
(gdb) p lnum
$37 = 133
I also see the following thing which is probably wrong in this stack trace:
(gdb) bt
#0 ml_get_buf (buf=0x83d0b0, lnum=133, will_change=0) at memline.c:2143
#1 0x00000000004ba367 in ml_get_cursor () at memline.c:2064
#2 0x00000000004cdaac in gchar_cursor () at misc1.c:2394
#3 0x000000000042a789 in stop_insert (end_insert_pos=0x83b870, esc=1)
at edit.c:6435
#4 0x000000000042c968 in ins_esc (count=0x7fff8c049c68, cmdchar=65,
nomove=0) at edit.c:7954
#5 0x0000000000421a86 in edit (cmdchar=65, startln=0, count=-1) at edit.c:927
#6 0x00000000004f66f4 in invoke_edit (cap=0x7fff8c049db0, repl=0,
cmd=65, startln=0) at normal.c:8888
#7 0x00000000004f6691 in nv_edit (cap=0x7fff8c049db0) at normal.c:8861
#8 0x00000000004e946d in normal_cmd (oap=0x7fff8c049e80, toplevel=1)
at normal.c:1189
#9 0x00000000004a90a2 in main_loop (cmdwin=0, noexmode=0) at main.c:1180
#10 0x00000000004a8be8 in main (argc=2, argv=0x7fff8c04a178) at main.c:939
2058│ /*
2059│ * ml_get_cursor: get pointer to cursor position
2060│ */
2061│ char_u *
2062│ ml_get_cursor()
2063│ {
2064│ return (ml_get_buf(curbuf, curwin->w_cursor.lnum, FALSE) +
2065│
curwin->w_cursor.col);
2066├>}
At line 2064, ml_get_buf(...) returns an empty string "" (consistent
with the fact that my file has an empty line at line 133) but
curwin->w_cursor.col
is 2 which looks wrong. Adding 2 to the empty string goes beyond the
end of string.
So it seems that curwin->w_cursor.col is incorrect.
ml_get_cursor() ends up returning 32 in this case:
(gdb) p buf->b_ml.ml_line_ptr
$49 = (char_u *) 0x8f59a7 ""
(gdb) p ((char_u *) 0x8f59a7)[2]
$50 = 32 ' '
Since getchar_cursor() at edit.c:6435 returns 32, lines edit.c:6436 is
never executed so curwin->w_cursor.col is never decremented and remains 2
all the time.
I suspect that code should check the return code of del_char(TRUE)
at edit.c:6440 and break from the loop if it fails to avoid
an infinite loop. But I think that would only be working around
the real bug: curwin->w_cursor.col being incorrect.
Since I don't know how to systematically reproduce this bug, it's
hard to experiment to see how to fix it. Hopefully the above
information might be enough to figure it out. Sorry, no patch for
this yet.
Regards
-- Dominique
We can use the return value of del_char() to break the loop. But I
wonder how the cursor ever ended up pointing beyond the end of the line.
I suppose some auto-indenting was done, which the loop is supposed to
remove. Either something happened in between the auto-indenting and
setting end_insert_pos, or there never was any auto-indenting.
--
ARTHUR: Listen, old crone! Unless you tell us where we can buy a shrubbery,
my friend and I will ... we will say "Ni!"
CRONE: Do your worst!
"Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD
/// Bram Moolenaar -- Br...@Moolenaar.net -- http://www.Moolenaar.net \\\
/// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\ download, build and distribute -- http://www.A-A-P.org ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///
I don't think I indented anything since I was just checking
out the file (it was thus read-only before checking out).
The perforce plugin (perforce-4.1.zip available at
http://www.vim.org/scripts/script.php?script_id=240) did
check-out the file, but Vim entered the endless loop
right afterwards before I got a chance to modify it. I tried
to reproduce the bug without success so far. But since
I saw this bug more than once in the past, I may see it
again.
In the mean time, I've added the following assert in
ml_get_cursor() to catch the bug if cursor happens to be
beyond the end of line again (so far it does not happen):
2061 char_u *
2062 ml_get_cursor()
2063 {
2064 char_u *tmp = ml_get_buf(curbuf, curwin->w_cursor.lnum, FALSE);
2065 int len = STRLEN(tmp);
2066 assert(curwin->w_cursor.col <= len);
2067 return (tmp + curwin->w_cursor.col);
2068 }
-- Dominique