Skip to content

Commit d3c907b

Browse files
committed
patch 7.4.2223
Problem: Buffer overflow when using latin1 character with feedkeys(). Solution: Check for an illegal character. Add a test.
1 parent 6bff02e commit d3c907b

11 files changed

Lines changed: 67 additions & 48 deletions

File tree

src/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2114,6 +2114,7 @@ test_arglist \
21142114
test_set \
21152115
test_signs \
21162116
test_sort \
2117+
test_source_utf8 \
21172118
test_startup \
21182119
test_startup_utf8 \
21192120
test_stat \

src/evalfunc.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11166,7 +11166,7 @@ f_strgetchar(typval_T *argvars, typval_T *rettv)
1116611166
break;
1116711167
}
1116811168
--charidx;
11169-
byteidx += mb_cptr2len(str + byteidx);
11169+
byteidx += MB_CPTR2LEN(str + byteidx);
1117011170
}
1117111171
}
1117211172
#else
@@ -11326,7 +11326,7 @@ f_strcharpart(typval_T *argvars, typval_T *rettv)
1132611326
if (nchar > 0)
1132711327
while (nchar > 0 && nbyte < slen)
1132811328
{
11329-
nbyte += mb_cptr2len(p + nbyte);
11329+
nbyte += MB_CPTR2LEN(p + nbyte);
1133011330
--nchar;
1133111331
}
1133211332
else
@@ -11341,7 +11341,7 @@ f_strcharpart(typval_T *argvars, typval_T *rettv)
1134111341
if (off < 0)
1134211342
len += 1;
1134311343
else
11344-
len += mb_cptr2len(p + off);
11344+
len += MB_CPTR2LEN(p + off);
1134511345
--charlen;
1134611346
}
1134711347
}

src/getchar.c

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4658,8 +4658,16 @@ vim_strsave_escape_csi(
46584658
char_u *res;
46594659
char_u *s, *d;
46604660

4661-
/* Need a buffer to hold up to three times as much. */
4662-
res = alloc((unsigned)(STRLEN(p) * 3) + 1);
4661+
/* Need a buffer to hold up to three times as much. Four in case of an
4662+
* illegal utf-8 byte:
4663+
* 0xc0 -> 0xc3 0x80 -> 0xc3 K_SPECIAL KS_SPECIAL KE_FILLER */
4664+
res = alloc((unsigned)(STRLEN(p) *
4665+
#ifdef FEAT_MBYTE
4666+
4
4667+
#else
4668+
3
4669+
#endif
4670+
) + 1);
46634671
if (res != NULL)
46644672
{
46654673
d = res;
@@ -4674,22 +4682,10 @@ vim_strsave_escape_csi(
46744682
}
46754683
else
46764684
{
4677-
#ifdef FEAT_MBYTE
4678-
int len = mb_char2len(PTR2CHAR(s));
4679-
int len2 = mb_ptr2len(s);
4680-
#endif
46814685
/* Add character, possibly multi-byte to destination, escaping
4682-
* CSI and K_SPECIAL. */
4686+
* CSI and K_SPECIAL. Be careful, it can be an illegal byte! */
46834687
d = add_char2buf(PTR2CHAR(s), d);
4684-
#ifdef FEAT_MBYTE
4685-
while (len < len2)
4686-
{
4687-
/* add following combining char */
4688-
d = add_char2buf(PTR2CHAR(s + len), d);
4689-
len += mb_char2len(PTR2CHAR(s + len));
4690-
}
4691-
#endif
4692-
mb_ptr_adv(s);
4688+
s += MB_CPTR2LEN(s);
46934689
}
46944690
}
46954691
*d = NUL;

src/macros.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,14 +274,15 @@
274274
/* Backup multi-byte pointer. Only use with "p" > "s" ! */
275275
# define mb_ptr_back(s, p) p -= has_mbyte ? ((*mb_head_off)(s, p - 1) + 1) : 1
276276
/* get length of multi-byte char, not including composing chars */
277-
# define mb_cptr2len(p) (enc_utf8 ? utf_ptr2len(p) : (*mb_ptr2len)(p))
277+
# define MB_CPTR2LEN(p) (enc_utf8 ? utf_ptr2len(p) : (*mb_ptr2len)(p))
278278

279279
# define MB_COPY_CHAR(f, t) if (has_mbyte) mb_copy_char(&f, &t); else *t++ = *f++
280280
# define MB_CHARLEN(p) (has_mbyte ? mb_charlen(p) : (int)STRLEN(p))
281281
# define MB_CHAR2LEN(c) (has_mbyte ? mb_char2len(c) : 1)
282282
# define PTR2CHAR(p) (has_mbyte ? mb_ptr2char(p) : (int)*(p))
283283
#else
284284
# define MB_PTR2LEN(p) 1
285+
# define MB_CPTR2LEN(p) 1
285286
# define mb_ptr_adv(p) ++p
286287
# define mb_cptr_adv(p) ++p
287288
# define mb_ptr_back(s, p) --p

src/os_unix.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4806,7 +4806,7 @@ mch_call_shell(
48064806
* round. */
48074807
for (p = buffer; p < buffer + len; p += l)
48084808
{
4809-
l = mb_cptr2len(p);
4809+
l = MB_CPTR2LEN(p);
48104810
if (l == 0)
48114811
l = 1; /* NUL byte? */
48124812
else if (MB_BYTE2LEN(*p) != l)

src/os_win32.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4370,7 +4370,7 @@ dump_pipe(int options,
43704370
* round. */
43714371
for (p = buffer; p < buffer + len; p += l)
43724372
{
4373-
l = mb_cptr2len(p);
4373+
l = MB_CPTR2LEN(p);
43744374
if (l == 0)
43754375
l = 1; /* NUL byte? */
43764376
else if (MB_BYTE2LEN(*p) != l)

src/spell.c

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5379,7 +5379,7 @@ suggest_trie_walk(
53795379
#ifdef FEAT_MBYTE
53805380
if (has_mbyte)
53815381
{
5382-
n = mb_cptr2len(p);
5382+
n = MB_CPTR2LEN(p);
53835383
c = mb_ptr2char(p);
53845384
if (p[n] == NUL)
53855385
c2 = NUL;
@@ -5477,9 +5477,9 @@ suggest_trie_walk(
54775477
#ifdef FEAT_MBYTE
54785478
if (has_mbyte)
54795479
{
5480-
n = mb_cptr2len(p);
5480+
n = MB_CPTR2LEN(p);
54815481
c = mb_ptr2char(p);
5482-
fl = mb_cptr2len(p + n);
5482+
fl = MB_CPTR2LEN(p + n);
54835483
c2 = mb_ptr2char(p + n);
54845484
if (!soundfold && !spell_iswordp(p + n + fl, curwin))
54855485
c3 = c; /* don't swap non-word char */
@@ -5596,10 +5596,10 @@ suggest_trie_walk(
55965596
#ifdef FEAT_MBYTE
55975597
if (has_mbyte)
55985598
{
5599-
n = mb_cptr2len(p);
5599+
n = MB_CPTR2LEN(p);
56005600
c = mb_ptr2char(p);
5601-
fl = mb_cptr2len(p + n);
5602-
fl += mb_cptr2len(p + n + fl);
5601+
fl = MB_CPTR2LEN(p + n);
5602+
fl += MB_CPTR2LEN(p + n + fl);
56035603
mch_memmove(p, p + n, fl);
56045604
mb_char2bytes(c, p + fl);
56055605
stack[depth].ts_fidxtry = sp->ts_fidx + n + fl;
@@ -5661,10 +5661,10 @@ suggest_trie_walk(
56615661
#ifdef FEAT_MBYTE
56625662
if (has_mbyte)
56635663
{
5664-
n = mb_cptr2len(p);
5665-
n += mb_cptr2len(p + n);
5664+
n = MB_CPTR2LEN(p);
5665+
n += MB_CPTR2LEN(p + n);
56665666
c = mb_ptr2char(p + n);
5667-
tl = mb_cptr2len(p + n);
5667+
tl = MB_CPTR2LEN(p + n);
56685668
mch_memmove(p + tl, p, n);
56695669
mb_char2bytes(c, p);
56705670
stack[depth].ts_fidxtry = sp->ts_fidx + n + tl;
@@ -5955,8 +5955,8 @@ find_keepcap_word(slang_T *slang, char_u *fword, char_u *kword)
59555955
#ifdef FEAT_MBYTE
59565956
if (has_mbyte)
59575957
{
5958-
flen = mb_cptr2len(fword + fwordidx[depth]);
5959-
ulen = mb_cptr2len(uword + uwordidx[depth]);
5958+
flen = MB_CPTR2LEN(fword + fwordidx[depth]);
5959+
ulen = MB_CPTR2LEN(uword + uwordidx[depth]);
59605960
}
59615961
else
59625962
#endif

src/testdir/test_alot_utf8.vim

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@
88
source test_expr_utf8.vim
99
source test_matchadd_conceal_utf8.vim
1010
source test_regexp_utf8.vim
11+
source test_source_utf8.vim

src/testdir/test_regexp_utf8.vim

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -92,18 +92,3 @@ func Test_classes_re2()
9292
call s:classes_test()
9393
set re=0
9494
endfunc
95-
96-
func Test_source_utf8()
97-
" check that sourcing a script with 0x80 as second byte works
98-
new
99-
call setline(1, [':%s/àx/--à1234--/g', ':%s/Àx/--À1234--/g'])
100-
write! Xscript
101-
bwipe!
102-
new
103-
call setline(1, [' àx ', ' Àx '])
104-
source! Xscript | echo
105-
call assert_equal(' --à1234-- ', getline(1))
106-
call assert_equal(' --À1234-- ', getline(2))
107-
bwipe!
108-
call delete('Xscript')
109-
endfunc

src/testdir/test_source_utf8.vim

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
" Test the :source! command
2+
if !has('multi_byte')
3+
finish
4+
endif
5+
6+
func Test_source_utf8()
7+
" check that sourcing a script with 0x80 as second byte works
8+
new
9+
call setline(1, [':%s/àx/--à1234--/g', ':%s/Àx/--À1234--/g'])
10+
write! Xscript
11+
bwipe!
12+
new
13+
call setline(1, [' àx ', ' Àx '])
14+
source! Xscript | echo
15+
call assert_equal(' --à1234-- ', getline(1))
16+
call assert_equal(' --À1234-- ', getline(2))
17+
bwipe!
18+
call delete('Xscript')
19+
endfunc
20+
21+
func Test_source_latin()
22+
" check that sourcing a latin1 script with a 0xc0 byte works
23+
new
24+
call setline(1, ["call feedkeys('r')", "call feedkeys('\xc0', 'xt')"])
25+
write! Xscript
26+
bwipe!
27+
new
28+
call setline(1, ['xxx'])
29+
source Xscript
30+
call assert_equal("\u00c0xx", getline(1))
31+
bwipe!
32+
call delete('Xscript')
33+
endfunc

0 commit comments

Comments
 (0)