patch 9.1.0413: smoothscroll may cause infinite loop

Commit: 
https://github.com/vim/vim/commit/eff20eb35d2dba413c6d115291dd9ddea705e802
Author: Christian Brabandt <c...@256bit.org>
Date:   Wed May 15 21:35:36 2024 +0200

    patch 9.1.0413: smoothscroll may cause infinite loop
    
    Problem:  smoothscroll may cause infinite loop, with
              very narrow windows
              (Jaehwang Jung, after v9.1.0280)
    Solution: Check for width1 being negative, verify
              that win_linetabsize does not overflow
    
    fixes: #14750
    closes: #14772
    
    Co-authored-by: zeertzjq <zeert...@outlook.com>
    Signed-off-by: Christian Brabandt <c...@256bit.org>

diff --git a/src/charset.c b/src/charset.c
index 470698f0e..9aa402ac5 100644
--- a/src/charset.c
+++ b/src/charset.c
@@ -765,10 +765,22 @@ linetabsize_str(char_u *s)
 linetabsize_col(int startcol, char_u *s)
 {
     chartabsize_T cts;
+    vimlong_T vcol;
 
     init_chartabsize_arg(&cts, curwin, 0, startcol, s, s);
+    vcol = cts.cts_vcol;
+
     while (*cts.cts_ptr != NUL)
-       cts.cts_vcol += lbr_chartabsize_adv(&cts);
+    {
+       vcol += lbr_chartabsize_adv(&cts);
+       if (vcol > MAXCOL)
+       {
+           cts.cts_vcol = MAXCOL;
+           break;
+       }
+       else
+           cts.cts_vcol = (int)vcol;
+    }
     clear_chartabsize_arg(&cts);
     return (int)cts.cts_vcol;
 }
@@ -840,22 +852,33 @@ linetabsize_no_outer(win_T *wp, linenr_T lnum)
     void
 win_linetabsize_cts(chartabsize_T *cts, colnr_T len)
 {
+    vimlong_T vcol = cts->cts_vcol;
 #ifdef FEAT_PROP_POPUP
     cts->cts_with_trailing = len == MAXCOL;
 #endif
     for ( ; *cts->cts_ptr != NUL && (len == MAXCOL || cts->cts_ptr < 
cts->cts_line + len);
                                                      MB_PTR_ADV(cts->cts_ptr))
-       cts->cts_vcol += win_lbr_chartabsize(cts, NULL);
+    {
+       vcol += win_lbr_chartabsize(cts, NULL);
+       if (vcol > MAXCOL)
+       {
+           cts->cts_vcol = MAXCOL;
+           break;
+       }
+       else
+           cts->cts_vcol = (int)vcol;
+    }
 #ifdef FEAT_PROP_POPUP
     // check for a virtual text at the end of a line or on an empty line
     if (len == MAXCOL && cts->cts_has_prop_with_text && *cts->cts_ptr == NUL)
     {
        (void)win_lbr_chartabsize(cts, NULL);
-       cts->cts_vcol += cts->cts_cur_text_width;
+       vcol += cts->cts_cur_text_width;
        // when properties are above or below the empty line must also be
        // counted
        if (cts->cts_ptr == cts->cts_line && cts->cts_prop_lines > 0)
-           ++cts->cts_vcol;
+           ++vcol;
+       cts->cts_vcol = vcol > MAXCOL ? MAXCOL : (int)vcol;
     }
 #endif
 }
diff --git a/src/move.c b/src/move.c
index 3e589caae..dd232686e 100644
--- a/src/move.c
+++ b/src/move.c
@@ -1630,6 +1630,7 @@ static void cursor_correct_sms(void)
     int            width2 = width1 + curwin_col_off2();
     int            so_cols = so == 0 ? 0 : width1 + (so - 1) * width2;
     int            space_cols = (curwin->w_height - 1) * width2;
+    int            overlap, top, bot;
     int            size = so == 0 ? 0 : win_linetabsize(curwin, 
curwin->w_topline,
                                    ml_get(curwin->w_topline), (colnr_T)MAXCOL);
 
@@ -1639,16 +1640,16 @@ static void cursor_correct_sms(void)
        so_cols = space_cols / 2;  // Not enough room: put cursor in the middle.
 
     // Not enough screen lines in topline: ignore 'scrolloff'.
-    while (so_cols > size && so_cols - width2 >= width1)
+    while (so_cols > size && so_cols - width2 >= width1 && width1 > 0)
        so_cols -= width2;
     if (so_cols >= width1 && so_cols > size)
        so_cols -= width1;
 
     // If there is no marker or we have non-zero scrolloff, just ignore it.
-    int overlap = (curwin->w_skipcol == 0 || so_cols != 0) ? 0
+    overlap = (curwin->w_skipcol == 0 || so_cols != 0) ? 0
                                            : sms_marker_overlap(curwin, -1);
-    int top = curwin->w_skipcol + overlap + so_cols;
-    int bot = curwin->w_skipcol + width1 + (curwin->w_height - 1) * width2
+    top = curwin->w_skipcol + overlap + so_cols;
+    bot = curwin->w_skipcol + width1 + (curwin->w_height - 1) * width2
                                                                    - so_cols;
     validate_virtcol();
     colnr_T col = curwin->w_virtcol;
diff --git a/src/testdir/test_normal.vim b/src/testdir/test_normal.vim
index 5cbf681ea..09ae42c16 100644
--- a/src/testdir/test_normal.vim
+++ b/src/testdir/test_normal.vim
@@ -4268,4 +4268,14 @@ func Test_halfpage_longline()
   call assert_equal(2, line('.'))
   bwipe!
 endfunc
+
+" Test for Ctrl-E with long line and very narrow window,
+" used to cause an inifite loop
+func Test_scroll_longline_no_loop()
+  4vnew
+  setl smoothscroll number showbreak=> scrolloff=2
+  call setline(1, repeat(['Lorem ipsum dolor sit amet, consectetur adipiscing 
elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.'], 3))
+  exe "normal! \<C-E>"
+  bwipe!
+endfunc
 " vim: shiftwidth=2 sts=2 expandtab nofoldenable
diff --git a/src/version.c b/src/version.c
index 834954af7..b79693c6a 100644
--- a/src/version.c
+++ b/src/version.c
@@ -704,6 +704,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    413,
 /**/
     412,
 /**/

-- 
-- 
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 vim_dev+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/E1s7KYj-003vsL-23%40256bit.org.

Reply via email to