To: vim_dev@googlegroups.com Subject: Patch 7.4.2223 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 7.4.2223 Problem: Buffer overflow when using latin1 character with feedkeys(). Solution: Check for an illegal character. Add a test. Files: src/testdir/test_regexp_utf8.vim, src/testdir/test_source_utf8.vim, src/testdir/test_alot_utf8.vim, src/Makefile, src/getchar.c, src/macros.h, src/evalfunc.c, src/os_unix.c, src/os_win32.c, src/spell.c *** ../vim-7.4.2222/src/testdir/test_regexp_utf8.vim 2016-08-16 22:50:50.758254682 +0200 --- src/testdir/test_regexp_utf8.vim 2016-08-17 20:17:41.702422218 +0200 *************** *** 92,109 **** call s:classes_test() set re=0 endfunc - - func Test_source_utf8() - " check that sourcing a script with 0x80 as second byte works - new - call setline(1, [':%s/àx/--à1234--/g', ':%s/Àx/--À1234--/g']) - write! Xscript - bwipe! - new - call setline(1, [' àx ', ' Àx ']) - source! Xscript | echo - call assert_equal(' --à1234-- ', getline(1)) - call assert_equal(' --À1234-- ', getline(2)) - bwipe! - call delete('Xscript') - endfunc --- 92,94 ---- *** ../vim-7.4.2222/src/testdir/test_source_utf8.vim 2016-08-17 21:30:50.354447196 +0200 --- src/testdir/test_source_utf8.vim 2016-08-17 21:28:17.083826957 +0200 *************** *** 0 **** --- 1,33 ---- + " Test the :source! command + if !has('multi_byte') + finish + endif + + func Test_source_utf8() + " check that sourcing a script with 0x80 as second byte works + new + call setline(1, [':%s/àx/--à1234--/g', ':%s/Àx/--À1234--/g']) + write! Xscript + bwipe! + new + call setline(1, [' àx ', ' Àx ']) + source! Xscript | echo + call assert_equal(' --à1234-- ', getline(1)) + call assert_equal(' --À1234-- ', getline(2)) + bwipe! + call delete('Xscript') + endfunc + + func Test_source_latin() + " check that sourcing a latin1 script with a 0xc0 byte works + new + call setline(1, ["call feedkeys('r')", "call feedkeys('\xc0', 'xt')"]) + write! Xscript + bwipe! + new + call setline(1, ['xxx']) + source Xscript + call assert_equal("\u00c0xx", getline(1)) + bwipe! + call delete('Xscript') + endfunc *** ../vim-7.4.2222/src/testdir/test_alot_utf8.vim 2016-07-21 20:33:28.835262339 +0200 --- src/testdir/test_alot_utf8.vim 2016-08-17 21:29:14.823307132 +0200 *************** *** 8,10 **** --- 8,11 ---- source test_expr_utf8.vim source test_matchadd_conceal_utf8.vim source test_regexp_utf8.vim + source test_source_utf8.vim *** ../vim-7.4.2222/src/Makefile 2016-08-14 15:31:53.353671912 +0200 --- src/Makefile 2016-08-17 21:29:25.523210804 +0200 *************** *** 2114,2119 **** --- 2114,2120 ---- test_set \ test_signs \ test_sort \ + test_source_utf8 \ test_startup \ test_startup_utf8 \ test_stat \ *** ../vim-7.4.2222/src/getchar.c 2016-08-16 22:50:50.754254718 +0200 --- src/getchar.c 2016-08-17 21:06:50.959528112 +0200 *************** *** 4658,4665 **** char_u *res; char_u *s, *d; ! /* Need a buffer to hold up to three times as much. */ ! res = alloc((unsigned)(STRLEN(p) * 3) + 1); if (res != NULL) { d = res; --- 4658,4673 ---- char_u *res; char_u *s, *d; ! /* Need a buffer to hold up to three times as much. Four in case of an ! * illegal utf-8 byte: ! * 0xc0 -> 0xc3 0x80 -> 0xc3 K_SPECIAL KS_SPECIAL KE_FILLER */ ! res = alloc((unsigned)(STRLEN(p) * ! #ifdef FEAT_MBYTE ! 4 ! #else ! 3 ! #endif ! ) + 1); if (res != NULL) { d = res; *************** *** 4674,4695 **** } else { - #ifdef FEAT_MBYTE - int len = mb_char2len(PTR2CHAR(s)); - int len2 = mb_ptr2len(s); - #endif /* Add character, possibly multi-byte to destination, escaping ! * CSI and K_SPECIAL. */ d = add_char2buf(PTR2CHAR(s), d); ! #ifdef FEAT_MBYTE ! while (len < len2) ! { ! /* add following combining char */ ! d = add_char2buf(PTR2CHAR(s + len), d); ! len += mb_char2len(PTR2CHAR(s + len)); ! } ! #endif ! mb_ptr_adv(s); } } *d = NUL; --- 4682,4691 ---- } else { /* Add character, possibly multi-byte to destination, escaping ! * CSI and K_SPECIAL. Be careful, it can be an illegal byte! */ d = add_char2buf(PTR2CHAR(s), d); ! s += MB_CPTR2LEN(s); } } *d = NUL; *** ../vim-7.4.2222/src/macros.h 2016-07-17 20:37:38.235378864 +0200 --- src/macros.h 2016-08-17 21:08:28.650636119 +0200 *************** *** 274,280 **** /* Backup multi-byte pointer. Only use with "p" > "s" ! */ # define mb_ptr_back(s, p) p -= has_mbyte ? ((*mb_head_off)(s, p - 1) + 1) : 1 /* get length of multi-byte char, not including composing chars */ ! # define mb_cptr2len(p) (enc_utf8 ? utf_ptr2len(p) : (*mb_ptr2len)(p)) # define MB_COPY_CHAR(f, t) if (has_mbyte) mb_copy_char(&f, &t); else *t++ = *f++ # define MB_CHARLEN(p) (has_mbyte ? mb_charlen(p) : (int)STRLEN(p)) --- 274,280 ---- /* Backup multi-byte pointer. Only use with "p" > "s" ! */ # define mb_ptr_back(s, p) p -= has_mbyte ? ((*mb_head_off)(s, p - 1) + 1) : 1 /* get length of multi-byte char, not including composing chars */ ! # define MB_CPTR2LEN(p) (enc_utf8 ? utf_ptr2len(p) : (*mb_ptr2len)(p)) # define MB_COPY_CHAR(f, t) if (has_mbyte) mb_copy_char(&f, &t); else *t++ = *f++ # define MB_CHARLEN(p) (has_mbyte ? mb_charlen(p) : (int)STRLEN(p)) *************** *** 282,287 **** --- 282,288 ---- # define PTR2CHAR(p) (has_mbyte ? mb_ptr2char(p) : (int)*(p)) #else # define MB_PTR2LEN(p) 1 + # define MB_CPTR2LEN(p) 1 # define mb_ptr_adv(p) ++p # define mb_cptr_adv(p) ++p # define mb_ptr_back(s, p) --p *** ../vim-7.4.2222/src/evalfunc.c 2016-08-15 22:16:21.557888355 +0200 --- src/evalfunc.c 2016-08-17 21:07:28.759182915 +0200 *************** *** 11166,11172 **** break; } --charidx; ! byteidx += mb_cptr2len(str + byteidx); } } #else --- 11166,11172 ---- break; } --charidx; ! byteidx += MB_CPTR2LEN(str + byteidx); } } #else *************** *** 11326,11332 **** if (nchar > 0) while (nchar > 0 && nbyte < slen) { ! nbyte += mb_cptr2len(p + nbyte); --nchar; } else --- 11326,11332 ---- if (nchar > 0) while (nchar > 0 && nbyte < slen) { ! nbyte += MB_CPTR2LEN(p + nbyte); --nchar; } else *************** *** 11341,11347 **** if (off < 0) len += 1; else ! len += mb_cptr2len(p + off); --charlen; } } --- 11341,11347 ---- if (off < 0) len += 1; else ! len += MB_CPTR2LEN(p + off); --charlen; } } *** ../vim-7.4.2222/src/os_unix.c 2016-08-14 18:23:16.755039539 +0200 --- src/os_unix.c 2016-08-17 21:07:35.983116953 +0200 *************** *** 4806,4812 **** * round. */ for (p = buffer; p < buffer + len; p += l) { ! l = mb_cptr2len(p); if (l == 0) l = 1; /* NUL byte? */ else if (MB_BYTE2LEN(*p) != l) --- 4806,4812 ---- * round. */ for (p = buffer; p < buffer + len; p += l) { ! l = MB_CPTR2LEN(p); if (l == 0) l = 1; /* NUL byte? */ else if (MB_BYTE2LEN(*p) != l) *** ../vim-7.4.2222/src/os_win32.c 2016-08-04 22:00:07.756346935 +0200 --- src/os_win32.c 2016-08-17 21:07:48.938998658 +0200 *************** *** 4370,4376 **** * round. */ for (p = buffer; p < buffer + len; p += l) { ! l = mb_cptr2len(p); if (l == 0) l = 1; /* NUL byte? */ else if (MB_BYTE2LEN(*p) != l) --- 4370,4376 ---- * round. */ for (p = buffer; p < buffer + len; p += l) { ! l = MB_CPTR2LEN(p); if (l == 0) l = 1; /* NUL byte? */ else if (MB_BYTE2LEN(*p) != l) *** ../vim-7.4.2222/src/spell.c 2016-07-24 21:58:39.716057524 +0200 --- src/spell.c 2016-08-17 21:08:21.318703048 +0200 *************** *** 5379,5385 **** #ifdef FEAT_MBYTE if (has_mbyte) { ! n = mb_cptr2len(p); c = mb_ptr2char(p); if (p[n] == NUL) c2 = NUL; --- 5379,5385 ---- #ifdef FEAT_MBYTE if (has_mbyte) { ! n = MB_CPTR2LEN(p); c = mb_ptr2char(p); if (p[n] == NUL) c2 = NUL; *************** *** 5477,5485 **** #ifdef FEAT_MBYTE if (has_mbyte) { ! n = mb_cptr2len(p); c = mb_ptr2char(p); ! fl = mb_cptr2len(p + n); c2 = mb_ptr2char(p + n); if (!soundfold && !spell_iswordp(p + n + fl, curwin)) c3 = c; /* don't swap non-word char */ --- 5477,5485 ---- #ifdef FEAT_MBYTE if (has_mbyte) { ! n = MB_CPTR2LEN(p); c = mb_ptr2char(p); ! fl = MB_CPTR2LEN(p + n); c2 = mb_ptr2char(p + n); if (!soundfold && !spell_iswordp(p + n + fl, curwin)) c3 = c; /* don't swap non-word char */ *************** *** 5596,5605 **** #ifdef FEAT_MBYTE if (has_mbyte) { ! n = mb_cptr2len(p); c = mb_ptr2char(p); ! fl = mb_cptr2len(p + n); ! fl += mb_cptr2len(p + n + fl); mch_memmove(p, p + n, fl); mb_char2bytes(c, p + fl); stack[depth].ts_fidxtry = sp->ts_fidx + n + fl; --- 5596,5605 ---- #ifdef FEAT_MBYTE if (has_mbyte) { ! n = MB_CPTR2LEN(p); c = mb_ptr2char(p); ! fl = MB_CPTR2LEN(p + n); ! fl += MB_CPTR2LEN(p + n + fl); mch_memmove(p, p + n, fl); mb_char2bytes(c, p + fl); stack[depth].ts_fidxtry = sp->ts_fidx + n + fl; *************** *** 5661,5670 **** #ifdef FEAT_MBYTE if (has_mbyte) { ! n = mb_cptr2len(p); ! n += mb_cptr2len(p + n); c = mb_ptr2char(p + n); ! tl = mb_cptr2len(p + n); mch_memmove(p + tl, p, n); mb_char2bytes(c, p); stack[depth].ts_fidxtry = sp->ts_fidx + n + tl; --- 5661,5670 ---- #ifdef FEAT_MBYTE if (has_mbyte) { ! n = MB_CPTR2LEN(p); ! n += MB_CPTR2LEN(p + n); c = mb_ptr2char(p + n); ! tl = MB_CPTR2LEN(p + n); mch_memmove(p + tl, p, n); mb_char2bytes(c, p); stack[depth].ts_fidxtry = sp->ts_fidx + n + tl; *************** *** 5955,5962 **** #ifdef FEAT_MBYTE if (has_mbyte) { ! flen = mb_cptr2len(fword + fwordidx[depth]); ! ulen = mb_cptr2len(uword + uwordidx[depth]); } else #endif --- 5955,5962 ---- #ifdef FEAT_MBYTE if (has_mbyte) { ! flen = MB_CPTR2LEN(fword + fwordidx[depth]); ! ulen = MB_CPTR2LEN(uword + uwordidx[depth]); } else #endif *** ../vim-7.4.2222/src/version.c 2016-08-16 22:50:50.758254682 +0200 --- src/version.c 2016-08-17 20:59:12.907717106 +0200 *************** *** 765,766 **** --- 765,768 ---- { /* Add new patch number below this line */ + /**/ + 2223, /**/ -- How To Keep A Healthy Level Of Insanity: 17. When the money comes out the ATM, scream "I won!, I won! 3rd time this week!!!!!" /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///