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 #8841)
diff --git a/src/drawline.c b/src/drawline.c
index 98d7693..2ad83f4 100644
--- a/src/drawline.c
+++ b/src/drawline.c
@@ -2109,55 +2109,60 @@
 			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
index 6f12b5f..0d77dbf 100644
--- a/src/testdir/test_listlbr_utf8.vim
+++ b/src/testdir/test_listlbr_utf8.vim
@@ -70,6 +70,16 @@
   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
index 0eb6899..979c039 100644
--- a/src/version.c
+++ b/src/version.c
@@ -756,6 +756,8 @@
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    3410,
+/**/
     3409,
 /**/
     3408,