# HG changeset patch # User Bram Moolenaar # Date 1631041205 -7200 # Node ID 24b80aa4dd2e4e88b119dc1c0cc34cb52e010e4a # Parent 8d0ecfbcc62af454295e0febfa6c021ac910e3a0 patch 8.2.3410: crash with linebreak, listchars and large tabstop Commit: https://github.com/vim/vim/commit/89a54b413a8c96206ce7e038dde81a6eff6cd6b8 Author: Bram Moolenaar Date: Tue Sep 7 20:45:31 2021 +0200 patch 8.2.3410: crash with linebreak, listchars and large tabstop Problem: Crash with linebreak, listchars and large tabstop. Solution: Account for different size listchars for a tab. (closes https://github.com/vim/vim/issues/8841) diff --git a/src/drawline.c b/src/drawline.c --- a/src/drawline.c +++ b/src/drawline.c @@ -2109,55 +2109,60 @@ win_line( int i; int saved_nextra = n_extra; -#ifdef FEAT_CONCEAL +# ifdef FEAT_CONCEAL if (vcol_off > 0) // there are characters to conceal tab_len += vcol_off; + // boguscols before FIX_FOR_BOGUSCOLS macro from above if (wp->w_p_list && wp->w_lcs_chars.tab1 && old_boguscols > 0 && n_extra > tab_len) tab_len += n_extra - tab_len; -#endif - - // if n_extra > 0, it gives the number of chars, to +# endif + // If n_extra > 0, it gives the number of chars, to // use for a tab, else we need to calculate the width - // for a tab + // for a tab. len = (tab_len * mb_char2len(wp->w_lcs_chars.tab2)); + if (wp->w_lcs_chars.tab3) + len += mb_char2len(wp->w_lcs_chars.tab3); if (n_extra > 0) len += n_extra - tab_len; c = wp->w_lcs_chars.tab1; p = alloc(len + 1); - vim_memset(p, ' ', len); - p[len] = NUL; - vim_free(p_extra_free); - p_extra_free = p; - for (i = 0; i < tab_len; i++) + if (p == NULL) + n_extra = 0; + else { - int lcs = wp->w_lcs_chars.tab2; - - if (*p == NUL) + vim_memset(p, ' ', len); + p[len] = NUL; + vim_free(p_extra_free); + p_extra_free = p; + for (i = 0; i < tab_len; i++) { - tab_len = i; - break; - } + int lcs = wp->w_lcs_chars.tab2; - // if tab3 is given, need to change the char - // for tab - if (wp->w_lcs_chars.tab3 && i == tab_len - 1) - lcs = wp->w_lcs_chars.tab3; - mb_char2bytes(lcs, p); - p += mb_char2len(lcs); - n_extra += mb_char2len(lcs) + if (*p == NUL) + { + tab_len = i; + break; + } + + // if tab3 is given, use it for the last char + if (wp->w_lcs_chars.tab3 && i == tab_len - 1) + lcs = wp->w_lcs_chars.tab3; + p += mb_char2bytes(lcs, p); + n_extra += mb_char2len(lcs) - (saved_nextra > 0 ? 1 : 0); + } + p_extra = p_extra_free; +# ifdef FEAT_CONCEAL + // n_extra will be increased by FIX_FOX_BOGUSCOLS + // macro below, so need to adjust for that here + if (vcol_off > 0) + n_extra -= vcol_off; +# endif } - p_extra = p_extra_free; -#ifdef FEAT_CONCEAL - // n_extra will be increased by FIX_FOX_BOGUSCOLS - // macro below, so need to adjust for that here - if (vcol_off > 0) - n_extra -= vcol_off; -#endif } #endif #ifdef FEAT_CONCEAL diff --git a/src/testdir/test_listlbr_utf8.vim b/src/testdir/test_listlbr_utf8.vim --- a/src/testdir/test_listlbr_utf8.vim +++ b/src/testdir/test_listlbr_utf8.vim @@ -70,6 +70,16 @@ func Test_nolinebreak_with_list() call s:close_windows() endfunc +" this was causing a crash +func Test_linebreak_with_list_and_tabs() + set linebreak list listchars=tab:⇤\ ⇥ tabstop=100 + new + call setline(1, "\t\t\ttext") + redraw + bwipe! + set nolinebreak nolist listchars&vim tabstop=8 +endfunc + func Test_linebreak_with_nolist() call s:test_windows('setl nolist') call setline(1, "\t*mask = nil;") diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -756,6 +756,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 3410, +/**/ 3409, /**/ 3408,