To: vim_dev@googlegroups.com Subject: Patch 9.0.0045 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 9.0.0045 Problem: Reading past end of completion with a long line and 'infercase' set. Solution: Allocate the string if needed. Files: src/insexpand.c, src/testdir/test_ins_complete.vim *** ../vim-9.0.0044/src/insexpand.c 2022-07-01 19:58:27.161837285 +0100 --- src/insexpand.c 2022-07-07 19:41:09.373495044 +0100 *************** *** 524,552 **** /* * Get the completed text by inferring the case of the originally typed text. */ static char_u * ins_compl_infercase_gettext( char_u *str, ! int actual_len, ! int actual_compl_length, ! int min_len) { int *wca; // Wide character array. char_u *p; int i, c; int has_lower = FALSE; int was_letter = FALSE; IObuff[0] = NUL; // Allocate wide character array for the completion and fill it. ! wca = ALLOC_MULT(int, actual_len); if (wca == NULL) return IObuff; p = str; ! for (i = 0; i < actual_len; ++i) if (has_mbyte) wca[i] = mb_ptr2char_adv(&p); else --- 524,555 ---- /* * Get the completed text by inferring the case of the originally typed text. + * If the result is in allocated memory "tofree" is set to it. */ static char_u * ins_compl_infercase_gettext( char_u *str, ! int char_len, ! int compl_char_len, ! int min_len, ! char_u **tofree) { int *wca; // Wide character array. char_u *p; int i, c; int has_lower = FALSE; int was_letter = FALSE; + garray_T gap; IObuff[0] = NUL; // Allocate wide character array for the completion and fill it. ! wca = ALLOC_MULT(int, char_len); if (wca == NULL) return IObuff; p = str; ! for (i = 0; i < char_len; ++i) if (has_mbyte) wca[i] = mb_ptr2char_adv(&p); else *************** *** 566,572 **** if (MB_ISUPPER(wca[i])) { // Rule 1 is satisfied. ! for (i = actual_compl_length; i < actual_len; ++i) wca[i] = MB_TOLOWER(wca[i]); break; } --- 569,575 ---- if (MB_ISUPPER(wca[i])) { // Rule 1 is satisfied. ! for (i = compl_char_len; i < char_len; ++i) wca[i] = MB_TOLOWER(wca[i]); break; } *************** *** 587,593 **** if (was_letter && MB_ISUPPER(c) && MB_ISLOWER(wca[i])) { // Rule 2 is satisfied. ! for (i = actual_compl_length; i < actual_len; ++i) wca[i] = MB_TOUPPER(wca[i]); break; } --- 590,596 ---- if (was_letter && MB_ISUPPER(c) && MB_ISLOWER(wca[i])) { // Rule 2 is satisfied. ! for (i = compl_char_len; i < char_len; ++i) wca[i] = MB_TOUPPER(wca[i]); break; } *************** *** 610,629 **** } // Generate encoding specific output from wide character array. - // Multi-byte characters can occupy up to five bytes more than - // ASCII characters, and we also need one byte for NUL, so stay - // six bytes away from the edge of IObuff. p = IObuff; i = 0; ! while (i < actual_len && (p - IObuff + 6) < IOSIZE) ! if (has_mbyte) p += (*mb_char2bytes)(wca[i++], p); else *(p++) = wca[i++]; ! *p = NUL; ! vim_free(wca); return IObuff; } --- 613,664 ---- } // Generate encoding specific output from wide character array. p = IObuff; i = 0; ! ga_init2(&gap, 1, 500); ! while (i < char_len) ! { ! if (gap.ga_data != NULL) ! { ! if (ga_grow(&gap, 10) == FAIL) ! { ! ga_clear(&gap); ! return (char_u *)"[failed]"; ! } ! p = (char_u *)gap.ga_data + gap.ga_len; ! if (has_mbyte) ! gap.ga_len += (*mb_char2bytes)(wca[i++], p); ! else ! { ! *p = wca[i++]; ! ++gap.ga_len; ! } ! } ! else if ((p - IObuff) + 6 >= IOSIZE) ! { ! // Multi-byte characters can occupy up to five bytes more than ! // ASCII characters, and we also need one byte for NUL, so when ! // getting to six bytes from the edge of IObuff switch to using a ! // growarray. Add the character in the next round. ! if (ga_grow(&gap, IOSIZE) == FAIL) ! return (char_u *)"[failed]"; ! STRCPY(gap.ga_data, IObuff); ! gap.ga_len = STRLEN(IObuff); ! } ! else if (has_mbyte) p += (*mb_char2bytes)(wca[i++], p); else *(p++) = wca[i++]; ! } vim_free(wca); + if (gap.ga_data != NULL) + { + *tofree = gap.ga_data; + return gap.ga_data; + } + + *p = NUL; return IObuff; } *************** *** 644,653 **** { char_u *str = str_arg; char_u *p; ! int actual_len; // Take multi-byte characters ! int actual_compl_length; // into account. int min_len; int flags = 0; if (p_ic && curbuf->b_p_inf && len > 0) { --- 679,690 ---- { char_u *str = str_arg; char_u *p; ! int char_len; // count multi-byte characters ! int compl_char_len; int min_len; int flags = 0; + int res; + char_u *tofree = NULL; if (p_ic && curbuf->b_p_inf && len > 0) { *************** *** 657,700 **** if (has_mbyte) { p = str; ! actual_len = 0; while (*p != NUL) { MB_PTR_ADV(p); ! ++actual_len; } } else ! actual_len = len; // Find actual length of original text. if (has_mbyte) { p = compl_orig_text; ! actual_compl_length = 0; while (*p != NUL) { MB_PTR_ADV(p); ! ++actual_compl_length; } } else ! actual_compl_length = compl_length; ! // "actual_len" may be smaller than "actual_compl_length" when using // thesaurus, only use the minimum when comparing. ! min_len = actual_len < actual_compl_length ! ? actual_len : actual_compl_length; ! str = ins_compl_infercase_gettext(str, actual_len, actual_compl_length, ! min_len); } if (cont_s_ipos) flags |= CP_CONT_S_IPOS; if (icase) flags |= CP_ICASE; ! return ins_compl_add(str, len, fname, NULL, NULL, dir, flags, FALSE); } /* --- 694,738 ---- if (has_mbyte) { p = str; ! char_len = 0; while (*p != NUL) { MB_PTR_ADV(p); ! ++char_len; } } else ! char_len = len; // Find actual length of original text. if (has_mbyte) { p = compl_orig_text; ! compl_char_len = 0; while (*p != NUL) { MB_PTR_ADV(p); ! ++compl_char_len; } } else ! compl_char_len = compl_length; ! // "char_len" may be smaller than "compl_char_len" when using // thesaurus, only use the minimum when comparing. ! min_len = char_len < compl_char_len ? char_len : compl_char_len; ! str = ins_compl_infercase_gettext(str, char_len, ! compl_char_len, min_len, &tofree); } if (cont_s_ipos) flags |= CP_CONT_S_IPOS; if (icase) flags |= CP_ICASE; ! res = ins_compl_add(str, len, fname, NULL, NULL, dir, flags, FALSE); ! vim_free(tofree); ! return res; } /* *** ../vim-9.0.0044/src/testdir/test_ins_complete.vim 2022-07-02 16:29:15.031193541 +0100 --- src/testdir/test_ins_complete.vim 2022-07-07 19:36:05.384951624 +0100 *************** *** 2097,2100 **** --- 2097,2116 ---- bwipe! endfunc + func Test_infercase_very_long_line() + " this was truncating the line when inferring case + new + let longLine = "blah "->repeat(300) + let verylongLine = "blah "->repeat(400) + call setline(1, verylongLine) + call setline(2, longLine) + set ic infercase + exe "normal 2Go\\\" + call assert_equal(longLine, getline(3)) + + bwipe! + set noic noinfercase + endfunc + + " vim: shiftwidth=2 sts=2 expandtab *** ../vim-9.0.0044/src/version.c 2022-07-06 13:31:25.299369947 +0100 --- src/version.c 2022-07-07 19:41:39.669563285 +0100 *************** *** 737,738 **** --- 737,740 ---- { /* Add new patch number below this line */ + /**/ + 45, /**/ -- hundred-and-one symptoms of being an internet addict: 77. The phone company asks you to test drive their new PBX system /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// \\\ \\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///