Mirror of the Vim source from https://github.com/vim/vim
Révision | fba9e366ced4df6a798c5ad3abc9940b409a606b (tree) |
---|---|
l'heure | 2022-07-01 06:15:03 |
Auteur | Bram Moolenaar <Bram@vim....> |
Commiter | Bram Moolenaar |
patch 9.0.0013: reproducing memory access errors can be difficult
Commit: https://github.com/vim/vim/commit/fa4873ccfc10e0f278dc46f39d00136fab059b19
Author: Bram Moolenaar <Bram@vim.org>
Date: Thu Jun 30 22:13:59 2022 +0100
@@ -268,6 +268,9 @@ | ||
268 | 268 | Current supported values for {name} are: |
269 | 269 | |
270 | 270 | {name} effect when {val} is non-zero ~ |
271 | + alloc_lines make a copy of every buffer line into allocated | |
272 | + memory, so that memory access errors can be found | |
273 | + by valgrind | |
271 | 274 | autoload `import autoload` will load the script right |
272 | 275 | away, not postponed until an item is used |
273 | 276 | char_avail disable the char_avail() function |
@@ -287,7 +290,8 @@ | ||
287 | 290 | uptime overrules sysinfo.uptime |
288 | 291 | vterm_title setting the window title by a job running in a |
289 | 292 | terminal window |
290 | - ALL clear all overrides ({val} is not used) | |
293 | + ALL clear all overrides, except alloc_lines ({val} is | |
294 | + not used) | |
291 | 295 | |
292 | 296 | "starting" is to be used when a test should behave like |
293 | 297 | startup was done. Since the tests are run by sourcing a |
@@ -1535,13 +1535,17 @@ | ||
1535 | 1535 | { |
1536 | 1536 | // End of C comment, indent should line up |
1537 | 1537 | // with the line containing the start of |
1538 | - // the comment | |
1538 | + // the comment. | |
1539 | 1539 | curwin->w_cursor.col = (colnr_T)(p - ptr); |
1540 | 1540 | if ((pos = findmatch(NULL, NUL)) != NULL) |
1541 | 1541 | { |
1542 | 1542 | curwin->w_cursor.lnum = pos->lnum; |
1543 | 1543 | newindent = get_indent(); |
1544 | + break; | |
1544 | 1545 | } |
1546 | + // this may make "ptr" invalid, get it again | |
1547 | + ptr = ml_get(curwin->w_cursor.lnum); | |
1548 | + p = ptr + curwin->w_cursor.col; | |
1545 | 1549 | } |
1546 | 1550 | } |
1547 | 1551 | } |
@@ -2794,8 +2794,6 @@ | ||
2794 | 2794 | break; |
2795 | 2795 | } |
2796 | 2796 | |
2797 | - l = ml_get_curline(); | |
2798 | - | |
2799 | 2797 | // If we're in a comment or raw string now, skip to |
2800 | 2798 | // the start of it. |
2801 | 2799 | trypos = ind_find_start_CORS(NULL); |
@@ -2806,6 +2804,8 @@ | ||
2806 | 2804 | continue; |
2807 | 2805 | } |
2808 | 2806 | |
2807 | + l = ml_get_curline(); | |
2808 | + | |
2809 | 2809 | // Skip preprocessor directives and blank lines. |
2810 | 2810 | if (cin_ispreproc_cont(&l, &curwin->w_cursor.lnum, |
2811 | 2811 | &amount)) |
@@ -2905,8 +2905,6 @@ | ||
2905 | 2905 | < ourscope - FIND_NAMESPACE_LIM) |
2906 | 2906 | break; |
2907 | 2907 | |
2908 | - l = ml_get_curline(); | |
2909 | - | |
2910 | 2908 | // If we're in a comment or raw string now, skip |
2911 | 2909 | // to the start of it. |
2912 | 2910 | trypos = ind_find_start_CORS(NULL); |
@@ -2917,6 +2915,8 @@ | ||
2917 | 2915 | continue; |
2918 | 2916 | } |
2919 | 2917 | |
2918 | + l = ml_get_curline(); | |
2919 | + | |
2920 | 2920 | // Skip preprocessor directives and blank lines. |
2921 | 2921 | if (cin_ispreproc_cont(&l, &curwin->w_cursor.lnum, |
2922 | 2922 | &amount)) |
@@ -3196,11 +3196,16 @@ | ||
3196 | 3196 | && trypos->col < tryposBrace->col))) |
3197 | 3197 | trypos = NULL; |
3198 | 3198 | |
3199 | + l = ml_get_curline(); | |
3200 | + | |
3199 | 3201 | // If we are looking for ',', we also look for matching |
3200 | 3202 | // braces. |
3201 | - if (trypos == NULL && terminated == ',' | |
3202 | - && find_last_paren(l, '{', '}')) | |
3203 | - trypos = find_start_brace(); | |
3203 | + if (trypos == NULL && terminated == ',') | |
3204 | + { | |
3205 | + if (find_last_paren(l, '{', '}')) | |
3206 | + trypos = find_start_brace(); | |
3207 | + l = ml_get_curline(); | |
3208 | + } | |
3204 | 3209 | |
3205 | 3210 | if (trypos != NULL) |
3206 | 3211 | { |
@@ -3233,6 +3238,7 @@ | ||
3233 | 3238 | --curwin->w_cursor.lnum; |
3234 | 3239 | curwin->w_cursor.col = 0; |
3235 | 3240 | } |
3241 | + l = ml_get_curline(); | |
3236 | 3242 | } |
3237 | 3243 | |
3238 | 3244 | // Get indent and pointer to text for current line, |
@@ -5013,7 +5013,7 @@ | ||
5013 | 5013 | mch_memmove(newp + col, ptr + i, |
5014 | 5014 | curbuf->b_ml.ml_line_len - col - i); |
5015 | 5015 | |
5016 | - if (curbuf->b_ml.ml_flags & ML_LINE_DIRTY) | |
5016 | + if (curbuf->b_ml.ml_flags & (ML_LINE_DIRTY | ML_ALLOCATED)) | |
5017 | 5017 | vim_free(curbuf->b_ml.ml_line_ptr); |
5018 | 5018 | curbuf->b_ml.ml_line_ptr = newp; |
5019 | 5019 | curbuf->b_ml.ml_line_len -= i; |
@@ -5232,10 +5232,10 @@ | ||
5232 | 5232 | } |
5233 | 5233 | |
5234 | 5234 | // try to advance to the cursor column |
5235 | + validate_virtcol(); | |
5235 | 5236 | temp = 0; |
5236 | 5237 | line = ptr = ml_get(lnum); |
5237 | 5238 | prev_ptr = ptr; |
5238 | - validate_virtcol(); | |
5239 | 5239 | while ((colnr_T)temp < curwin->w_virtcol && *ptr != NUL) |
5240 | 5240 | { |
5241 | 5241 | prev_ptr = ptr; |
@@ -1654,6 +1654,7 @@ | ||
1654 | 1654 | EXTERN int disable_vterm_title_for_testing INIT(= FALSE); |
1655 | 1655 | EXTERN long override_sysinfo_uptime INIT(= -1); |
1656 | 1656 | EXTERN int override_autoload INIT(= FALSE); |
1657 | +EXTERN int ml_get_alloc_lines INIT(= FALSE); | |
1657 | 1658 | |
1658 | 1659 | EXTERN int in_free_unref_items INIT(= FALSE); |
1659 | 1660 | #endif |
@@ -858,7 +858,8 @@ | ||
858 | 858 | if (buf->b_ml.ml_mfp == NULL) // not open |
859 | 859 | return; |
860 | 860 | mf_close(buf->b_ml.ml_mfp, del_file); // close the .swp file |
861 | - if (buf->b_ml.ml_line_lnum != 0 && (buf->b_ml.ml_flags & ML_LINE_DIRTY)) | |
861 | + if (buf->b_ml.ml_line_lnum != 0 | |
862 | + && (buf->b_ml.ml_flags & (ML_LINE_DIRTY | ML_ALLOCATED))) | |
862 | 863 | vim_free(buf->b_ml.ml_line_ptr); |
863 | 864 | vim_free(buf->b_ml.ml_stack); |
864 | 865 | #ifdef FEAT_BYTEOFF |
@@ -2620,7 +2621,6 @@ | ||
2620 | 2621 | --recursive; |
2621 | 2622 | } |
2622 | 2623 | ml_flush_line(buf); |
2623 | - buf->b_ml.ml_flags &= ~ML_LINE_DIRTY; | |
2624 | 2624 | errorret: |
2625 | 2625 | STRCPY(questions, "???"); |
2626 | 2626 | buf->b_ml.ml_line_len = 4; |
@@ -2686,17 +2686,44 @@ | ||
2686 | 2686 | buf->b_ml.ml_line_ptr = (char_u *)dp + start; |
2687 | 2687 | buf->b_ml.ml_line_len = len; |
2688 | 2688 | buf->b_ml.ml_line_lnum = lnum; |
2689 | - buf->b_ml.ml_flags &= ~ML_LINE_DIRTY; | |
2689 | + buf->b_ml.ml_flags &= ~(ML_LINE_DIRTY | ML_ALLOCATED); | |
2690 | 2690 | } |
2691 | 2691 | if (will_change) |
2692 | + { | |
2692 | 2693 | buf->b_ml.ml_flags |= (ML_LOCKED_DIRTY | ML_LOCKED_POS); |
2693 | - | |
2694 | +#ifdef FEAT_EVAL | |
2695 | + if (ml_get_alloc_lines && (buf->b_ml.ml_flags & ML_ALLOCATED)) | |
2696 | + // can't make the change in the data block | |
2697 | + buf->b_ml.ml_flags |= ML_LINE_DIRTY; | |
2698 | +#endif | |
2699 | + } | |
2700 | + | |
2701 | +#ifdef FEAT_EVAL | |
2702 | + if (ml_get_alloc_lines | |
2703 | + && (buf->b_ml.ml_flags & (ML_LINE_DIRTY | ML_ALLOCATED)) == 0) | |
2704 | + { | |
2705 | + char_u *p = alloc(buf->b_ml.ml_line_len); | |
2706 | + | |
2707 | + // make sure the text is in allocated memory | |
2708 | + if (p != NULL) | |
2709 | + { | |
2710 | + memmove(p, buf->b_ml.ml_line_ptr, buf->b_ml.ml_line_len); | |
2711 | + buf->b_ml.ml_line_ptr = p; | |
2712 | + buf->b_ml.ml_flags |= ML_ALLOCATED; | |
2713 | + if (will_change) | |
2714 | + // can't make the change in the data block | |
2715 | + buf->b_ml.ml_flags |= ML_LINE_DIRTY; | |
2716 | + } | |
2717 | + } | |
2718 | +#endif | |
2694 | 2719 | return buf->b_ml.ml_line_ptr; |
2695 | 2720 | } |
2696 | 2721 | |
2697 | 2722 | /* |
2698 | 2723 | * Check if a line that was just obtained by a call to ml_get |
2699 | 2724 | * is in allocated memory. |
2725 | + * This ignores ML_ALLOCATED to get the same behavior as without the test | |
2726 | + * override. | |
2700 | 2727 | */ |
2701 | 2728 | int |
2702 | 2729 | ml_line_alloced(void) |
@@ -3409,6 +3436,8 @@ | ||
3409 | 3436 | * "len_arg" is the length of the text, excluding NUL. |
3410 | 3437 | * If "has_props" is TRUE then "line_arg" includes the text properties and |
3411 | 3438 | * "len_arg" includes the NUL of the text. |
3439 | + * When "copy" is TRUE copy the text into allocated memory, otherwise | |
3440 | + * "line_arg" must be allocated and will be consumed here. | |
3412 | 3441 | */ |
3413 | 3442 | int |
3414 | 3443 | ml_replace_len( |
@@ -3454,7 +3483,6 @@ | ||
3454 | 3483 | { |
3455 | 3484 | // another line is buffered, flush it |
3456 | 3485 | ml_flush_line(curbuf); |
3457 | - curbuf->b_ml.ml_flags &= ~ML_LINE_DIRTY; | |
3458 | 3486 | |
3459 | 3487 | #ifdef FEAT_PROP_POPUP |
3460 | 3488 | if (curbuf->b_has_textprop && !has_props) |
@@ -3488,8 +3516,8 @@ | ||
3488 | 3516 | } |
3489 | 3517 | #endif |
3490 | 3518 | |
3491 | - if (curbuf->b_ml.ml_flags & ML_LINE_DIRTY) // same line allocated | |
3492 | - vim_free(curbuf->b_ml.ml_line_ptr); // free it | |
3519 | + if (curbuf->b_ml.ml_flags & (ML_LINE_DIRTY | ML_ALLOCATED)) | |
3520 | + vim_free(curbuf->b_ml.ml_line_ptr); // free allocated line | |
3493 | 3521 | |
3494 | 3522 | curbuf->b_ml.ml_line_ptr = line; |
3495 | 3523 | curbuf->b_ml.ml_line_len = len; |
@@ -4064,7 +4092,10 @@ | ||
4064 | 4092 | |
4065 | 4093 | entered = FALSE; |
4066 | 4094 | } |
4067 | - | |
4095 | + else if (buf->b_ml.ml_flags & ML_ALLOCATED) | |
4096 | + vim_free(buf->b_ml.ml_line_ptr); | |
4097 | + | |
4098 | + buf->b_ml.ml_flags &= ~(ML_LINE_DIRTY | ML_ALLOCATED); | |
4068 | 4099 | buf->b_ml.ml_line_lnum = 0; |
4069 | 4100 | } |
4070 | 4101 |
@@ -2741,13 +2741,15 @@ | ||
2741 | 2741 | if (nbbuf->insertDone) |
2742 | 2742 | nbbuf->modified = 1; |
2743 | 2743 | |
2744 | + // send the "insert" EVT | |
2745 | + newtxt = alloc(newlen + 1); | |
2746 | + vim_strncpy(newtxt, txt, newlen); | |
2747 | + | |
2748 | + // Note: this may make "txt" invalid | |
2744 | 2749 | pos.lnum = linenr; |
2745 | 2750 | pos.col = col; |
2746 | 2751 | off = pos2off(bufp, &pos); |
2747 | 2752 | |
2748 | - // send the "insert" EVT | |
2749 | - newtxt = alloc(newlen + 1); | |
2750 | - vim_strncpy(newtxt, txt, newlen); | |
2751 | 2753 | p = nb_quote(newtxt); |
2752 | 2754 | if (p != NULL) |
2753 | 2755 | { |
@@ -5120,6 +5120,8 @@ | ||
5120 | 5120 | count = (int)STRLEN(ptr) - pos.col; |
5121 | 5121 | netbeans_removed(curbuf, pos.lnum, pos.col, |
5122 | 5122 | (long)count); |
5123 | + // line may have been flushed, get it again | |
5124 | + ptr = ml_get(pos.lnum); | |
5123 | 5125 | netbeans_inserted(curbuf, pos.lnum, pos.col, |
5124 | 5126 | &ptr[pos.col], count); |
5125 | 5127 | } |
@@ -1273,6 +1273,8 @@ | ||
1273 | 1273 | |
1274 | 1274 | netbeans_removed(curbuf, pos.lnum, bd.textcol, |
1275 | 1275 | (long)bd.textlen); |
1276 | + // get the line again, it may have been flushed | |
1277 | + ptr = ml_get_buf(curbuf, pos.lnum, FALSE); | |
1276 | 1278 | netbeans_inserted(curbuf, pos.lnum, bd.textcol, |
1277 | 1279 | &ptr[bd.textcol], bd.textlen); |
1278 | 1280 | } |
@@ -1322,6 +1324,8 @@ | ||
1322 | 1324 | ptr = ml_get_buf(curbuf, pos.lnum, FALSE); |
1323 | 1325 | count = (int)STRLEN(ptr) - pos.col; |
1324 | 1326 | netbeans_removed(curbuf, pos.lnum, pos.col, (long)count); |
1327 | + // get the line again, it may have been flushed | |
1328 | + ptr = ml_get_buf(curbuf, pos.lnum, FALSE); | |
1325 | 1329 | netbeans_inserted(curbuf, pos.lnum, pos.col, |
1326 | 1330 | &ptr[pos.col], count); |
1327 | 1331 | pos.col = 0; |
@@ -1330,6 +1334,8 @@ | ||
1330 | 1334 | ptr = ml_get_buf(curbuf, pos.lnum, FALSE); |
1331 | 1335 | count = oap->end.col - pos.col + 1; |
1332 | 1336 | netbeans_removed(curbuf, pos.lnum, pos.col, (long)count); |
1337 | + // get the line again, it may have been flushed | |
1338 | + ptr = ml_get_buf(curbuf, pos.lnum, FALSE); | |
1333 | 1339 | netbeans_inserted(curbuf, pos.lnum, pos.col, |
1334 | 1340 | &ptr[pos.col], count); |
1335 | 1341 | } |
@@ -756,10 +756,11 @@ | ||
756 | 756 | int ml_stack_top; // current top of ml_stack |
757 | 757 | int ml_stack_size; // total number of entries in ml_stack |
758 | 758 | |
759 | -#define ML_EMPTY 1 // empty buffer | |
760 | -#define ML_LINE_DIRTY 2 // cached line was changed and allocated | |
761 | -#define ML_LOCKED_DIRTY 4 // ml_locked was changed | |
762 | -#define ML_LOCKED_POS 8 // ml_locked needs positive block number | |
759 | +#define ML_EMPTY 0x01 // empty buffer | |
760 | +#define ML_LINE_DIRTY 0x02 // cached line was changed and allocated | |
761 | +#define ML_LOCKED_DIRTY 0x04 // ml_locked was changed | |
762 | +#define ML_LOCKED_POS 0x08 // ml_locked needs positive block number | |
763 | +#define ML_ALLOCATED 0x10 // ml_line_ptr is an allocated copy | |
763 | 764 | int ml_flags; |
764 | 765 | |
765 | 766 | colnr_T ml_line_len; // length of the cached line, including NUL |
@@ -154,6 +154,10 @@ | ||
154 | 154 | " Prepare for calling test_garbagecollect_now(). |
155 | 155 | let v:testing = 1 |
156 | 156 | |
157 | +" By default, copy each buffer line into allocated memory, so that valgrind can | |
158 | +" detect accessing memory before and after it. | |
159 | +call test_override('alloc_lines', 1) | |
160 | + | |
157 | 161 | " Support function: get the alloc ID by name. |
158 | 162 | function GetAllocId(name) |
159 | 163 | exe 'split ' . s:srcdir . '/alloc.h' |
@@ -182,7 +186,7 @@ | ||
182 | 186 | " mode message. |
183 | 187 | set noshowmode |
184 | 188 | |
185 | - " Clear any overrides. | |
189 | + " Clear any overrides, except "alloc_lines". | |
186 | 190 | call test_override('ALL', 0) |
187 | 191 | |
188 | 192 | " Some tests wipe out buffers. To be consistent, always wipe out all |
@@ -10,7 +10,9 @@ | ||
10 | 10 | source view_util.vim |
11 | 11 | source screendump.vim |
12 | 12 | |
13 | -let s:input ="\tabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOP" | |
13 | +func SetUp() | |
14 | + let s:input ="\tabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOP" | |
15 | +endfunc | |
14 | 16 | |
15 | 17 | func s:screen_lines(lnum, width) abort |
16 | 18 | return ScreenLines([a:lnum, a:lnum + 2], a:width) |
@@ -714,6 +716,9 @@ | ||
714 | 716 | endfunc |
715 | 717 | |
716 | 718 | func Test_breakindent20_list() |
719 | + " FIXME - this should not matter | |
720 | + call test_override('alloc_lines', 0) | |
721 | + | |
717 | 722 | call s:test_windows('setl breakindent breakindentopt= linebreak') |
718 | 723 | " default: |
719 | 724 | call setline(1, [' 1. Congress shall make no law', |
@@ -830,6 +835,9 @@ | ||
830 | 835 | let lines = s:screen_lines2(1, 6, 20) |
831 | 836 | call s:compare_lines(expect, lines) |
832 | 837 | call s:close_windows('set breakindent& briopt& linebreak& list& listchars& showbreak&') |
838 | + | |
839 | + " FIXME - this should not matter | |
840 | + call test_override('alloc_lines', 1) | |
833 | 841 | endfunc |
834 | 842 | |
835 | 843 | " The following used to crash Vim. This is fixed by 8.2.3391. |
@@ -873,15 +881,20 @@ | ||
873 | 881 | endfunc |
874 | 882 | |
875 | 883 | func Test_no_spurious_match() |
884 | + " FIXME - fails under valgrind - this should not matter - timing issue? | |
885 | + call test_override('alloc_lines', 0) | |
886 | + | |
876 | 887 | let s:input = printf('- y %s y %s', repeat('x', 50), repeat('x', 50)) |
877 | 888 | call s:test_windows('setl breakindent breakindentopt=list:-1 formatlistpat=^- hls') |
878 | 889 | let @/ = '\%>3v[y]' |
879 | 890 | redraw! |
880 | 891 | call searchcount().total->assert_equal(1) |
892 | + | |
881 | 893 | " cleanup |
882 | 894 | set hls&vim |
883 | - let s:input = "\tabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOP" | |
884 | 895 | bwipeout! |
896 | + " FIXME - this should not matter | |
897 | + call test_override('alloc_lines', 1) | |
885 | 898 | endfunc |
886 | 899 | |
887 | 900 | func Test_no_extra_indent() |
@@ -945,8 +958,6 @@ | ||
945 | 958 | endfunc |
946 | 959 | |
947 | 960 | func Test_breakindent_column() |
948 | - " restore original | |
949 | - let s:input ="\tabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOP" | |
950 | 961 | call s:test_windows('setl breakindent breakindentopt=column:10') |
951 | 962 | redraw! |
952 | 963 | " 1) default: does not indent, too wide :( |
@@ -1860,6 +1860,9 @@ | ||
1860 | 1860 | call writefile(lines, 'Xtest_edit_insertmode_ex_edit') |
1861 | 1861 | |
1862 | 1862 | let buf = RunVimInTerminal('-S Xtest_edit_insertmode_ex_edit', #{rows: 6}) |
1863 | + " Somehow this can be very slow with valgrind. A separate TermWait() works | |
1864 | + " better than a longer time with WaitForAssert() (why?) | |
1865 | + call TermWait(buf, 1000) | |
1863 | 1866 | call WaitForAssert({-> assert_match('^-- INSERT --\s*$', term_getline(buf, 6))}) |
1864 | 1867 | call term_sendkeys(buf, "\<C-B>\<C-L>") |
1865 | 1868 | call WaitForAssert({-> assert_notmatch('^-- INSERT --\s*$', term_getline(buf, 6))}) |
@@ -287,7 +287,7 @@ | ||
287 | 287 | props + i * sizeof(textprop_T), |
288 | 288 | sizeof(textprop_T) * (proplen - i)); |
289 | 289 | |
290 | - if (buf->b_ml.ml_flags & ML_LINE_DIRTY) | |
290 | + if (buf->b_ml.ml_flags & (ML_LINE_DIRTY | ML_ALLOCATED)) | |
291 | 291 | vim_free(buf->b_ml.ml_line_ptr); |
292 | 292 | buf->b_ml.ml_line_ptr = newtext; |
293 | 293 | buf->b_ml.ml_line_len += sizeof(textprop_T); |
@@ -564,7 +564,7 @@ | ||
564 | 564 | mch_memmove(newtext, text, textlen); |
565 | 565 | if (len > 0) |
566 | 566 | mch_memmove(newtext + textlen, props, len); |
567 | - if (curbuf->b_ml.ml_flags & ML_LINE_DIRTY) | |
567 | + if (curbuf->b_ml.ml_flags & (ML_LINE_DIRTY | ML_ALLOCATED)) | |
568 | 568 | vim_free(curbuf->b_ml.ml_line_ptr); |
569 | 569 | curbuf->b_ml.ml_line_ptr = newtext; |
570 | 570 | curbuf->b_ml.ml_line_len = textlen + len; |
@@ -698,6 +698,8 @@ | ||
698 | 698 | // need to allocate the line now |
699 | 699 | if (newtext == NULL) |
700 | 700 | return; |
701 | + if (buf->b_ml.ml_flags & ML_ALLOCATED) | |
702 | + vim_free(buf->b_ml.ml_line_ptr); | |
701 | 703 | buf->b_ml.ml_line_ptr = newtext; |
702 | 704 | buf->b_ml.ml_flags |= ML_LINE_DIRTY; |
703 | 705 | } |
@@ -1273,6 +1275,8 @@ | ||
1273 | 1275 | return; |
1274 | 1276 | mch_memmove(newptr, buf->b_ml.ml_line_ptr, |
1275 | 1277 | buf->b_ml.ml_line_len); |
1278 | + if (buf->b_ml.ml_flags & ML_ALLOCATED) | |
1279 | + vim_free(buf->b_ml.ml_line_ptr); | |
1276 | 1280 | buf->b_ml.ml_line_ptr = newptr; |
1277 | 1281 | buf->b_ml.ml_flags |= ML_LINE_DIRTY; |
1278 | 1282 |
@@ -1766,8 +1770,13 @@ | ||
1766 | 1770 | colnr_T newlen = (int)textlen + wi * (colnr_T)sizeof(textprop_T); |
1767 | 1771 | |
1768 | 1772 | if ((curbuf->b_ml.ml_flags & ML_LINE_DIRTY) == 0) |
1769 | - curbuf->b_ml.ml_line_ptr = | |
1770 | - vim_memsave(curbuf->b_ml.ml_line_ptr, newlen); | |
1773 | + { | |
1774 | + char_u *p = vim_memsave(curbuf->b_ml.ml_line_ptr, newlen); | |
1775 | + | |
1776 | + if (curbuf->b_ml.ml_flags & ML_ALLOCATED) | |
1777 | + vim_free(curbuf->b_ml.ml_line_ptr); | |
1778 | + curbuf->b_ml.ml_line_ptr = p; | |
1779 | + } | |
1771 | 1780 | curbuf->b_ml.ml_flags |= ML_LINE_DIRTY; |
1772 | 1781 | curbuf->b_ml.ml_line_len = newlen; |
1773 | 1782 | } |
@@ -736,6 +736,8 @@ | ||
736 | 736 | static int included_patches[] = |
737 | 737 | { /* Add new patch number below this line */ |
738 | 738 | /**/ |
739 | + 13, | |
740 | +/**/ | |
739 | 741 | 12, |
740 | 742 | /**/ |
741 | 743 | 11, |