Commit: patch 9.2.0989: libvterm: hang when rendering REP with no preceding char

Christian Brabandt <[email protected]>
Newsgroups gmane.editors.vim.devel
Message-ID <[email protected]>
patch 9.2.0989: libvterm: hang when rendering REP with no preceding char

Commit: https://github.com/vim/vim/commit/785bb3e9b271eb377dbd4157ce281eac7f16a021
Author: Christian Brabandt <[email protected]>
Date:   Thu Aug 20 20:46:08 2026 +0000

    patch 9.2.0989: libvterm: hang when rendering REP with no preceding char
    
    Problem:  When libvterm receives the REP control (CSI b) it repeats the
              preceding graphic character by advancing the cursor by
              "combine_width".  When a graphic char was yet not printed, this
              resulted in an endless loop (Vadím Sukhomlínov).
    Solution: Ignore REP when no graphic character was printed yet, like xterm
              does.
    
    related: #21099
    
    Signed-off-by: Christian Brabandt <[email protected]>
    Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>

diff --git a/src/libvterm/src/state.c b/src/libvterm/src/state.c
index 70bce0a23..7a9732b58 100644
--- a/src/libvterm/src/state.c
+++ b/src/libvterm/src/state.c
@@ -1323,6 +1323,13 @@ static int on_csi(const char *leader, const long args[], int argcount, const cha
 
   case 0x62: { // REP - ECMA-48 8.3.103
     const int row_width = THISROWWIDTH(state);
+
+    // ECMA-48 repeats the preceding graphic character; when none was
+    // printed yet "combine_width" is zero and the loop below would never
+    // advance the cursor.  Ignore the control then, like xterm does.
+    if(state->combine_width < 1)
+      break;
+
     count = CSI_ARG_COUNT(args[0]);
     col = state->pos.col + count;
     UBOUND(col, row_width);
diff --git a/src/testdir/test_terminal3.vim b/src/testdir/test_terminal3.vim
index 7d67d6f68..263e9ee34 100644
--- a/src/testdir/test_terminal3.vim
+++ b/src/testdir/test_terminal3.vim
@@ -1396,4 +1396,27 @@ func Test_terminal_negative_col_oob()
   endfor
 endfunc
 
+" This caused a hang
+func Test_terminal_rep_no_preceding_char()
+  CheckUnix
+  CheckExecutable printf
+
+  " REP repeats the preceding graphic character.  When none was printed yet
+  " the repeat width in libvterm is zero, so the cursor never reached the end
+  " column and Vim looped forever while rendering the sequence.
+  let buf = term_start([&shell, &shellcmdflag, 'printf "%s" ' .. shellescape("\<ESC>[9b")],
+        \ #{term_rows: 10, term_cols: 40})
+  call TermWait(buf)
+  " Getting here without a hang is the test.
+  call assert_true(bufexists(buf))
+  exe 'bwipe! ' .. buf
+
+  " REP after a graphic character still repeats it.
+  let buf = term_start([&shell, &shellcmdflag, 'printf "%s" ' .. shellescape("X\<ESC>[4b")],
+        \ #{term_rows: 10, term_cols: 40})
+  call TermWait(buf)
+  call WaitForAssert({-> assert_equal('XXXXX', term_getline(buf, 1))})
+  exe 'bwipe! ' .. buf
+endfunc
+
 " vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/version.c b/src/version.c
index a8698a9fd..840e5cf8b 100644
--- a/src/version.c
+++ b/src/version.c
@@ -763,6 +763,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    989,
 /**/
     988,
 /**/

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups "vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
To view this discussion visit https://groups.google.com/d/msgid/vim_dev/E1wxAKs-00E7PI-3X%40256bit.org.
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.