summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2016-08-17 21:32:09 +0200
committerBram Moolenaar <Bram@vim.org>2016-08-17 21:32:09 +0200
commitd3c907b5d2b352482b580a0cf687cbbea4c19ea1 (patch)
tree4ef356217c0b95e6f6ee5b5d3bb756c103ef8b82
parent6bff02eb530aa29aafa2cb5627399837be7a5dd5 (diff)
patch 7.4.2223v7.4.2223
Problem: Buffer overflow when using latin1 character with feedkeys(). Solution: Check for an illegal character. Add a test.
-rw-r--r--src/Makefile1
-rw-r--r--src/evalfunc.c6
-rw-r--r--src/getchar.c28
-rw-r--r--src/macros.h3
-rw-r--r--src/os_unix.c2
-rw-r--r--src/os_win32.c2
-rw-r--r--src/spell.c22
-rw-r--r--src/testdir/test_alot_utf8.vim1
-rw-r--r--src/testdir/test_regexp_utf8.vim15
-rw-r--r--src/testdir/test_source_utf8.vim33
-rw-r--r--src/version.c2
11 files changed, 67 insertions, 48 deletions
diff --git a/src/Makefile b/src/Makefile
index 84ebdc61da..28b4b20fd0 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -2114,6 +2114,7 @@ test_arglist \
test_set \
test_signs \
test_sort \
+ test_source_utf8 \
test_startup \
test_startup_utf8 \
test_stat \
diff --git a/src/evalfunc.c b/src/evalfunc.c
index cc38d94c98..b427ecf7e1 100644
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -11166,7 +11166,7 @@ f_strgetchar(typval_T *argvars, typval_T *rettv)
break;
}
--charidx;
- byteidx += mb_cptr2len(str + byteidx);
+ byteidx += MB_CPTR2LEN(str + byteidx);
}
}
#else
@@ -11326,7 +11326,7 @@ f_strcharpart(typval_T *argvars, typval_T *rettv)
if (nchar > 0)
while (nchar > 0 && nbyte < slen)
{
- nbyte += mb_cptr2len(p + nbyte);
+ nbyte += MB_CPTR2LEN(p + nbyte);
--nchar;
}
else
@@ -11341,7 +11341,7 @@ f_strcharpart(typval_T *argvars, typval_T *rettv)
if (off < 0)
len += 1;
else
- len += mb_cptr2len(p + off);
+ len += MB_CPTR2LEN(p + off);
--charlen;
}
}
diff --git a/src/getchar.c b/src/getchar.c
index 1c170cc435..52b1853776 100644
--- a/src/getchar.c
+++ b/src/getchar.c
@@ -4658,8 +4658,16 @@ vim_strsave_escape_csi(
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);
+ /* 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,22 +4682,10 @@ vim_strsave_escape_csi(
}
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. */
+ * CSI and K_SPECIAL. Be careful, it can be an illegal byte! */
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);
+ s += MB_CPTR2LEN(s);
}
}
*d = NUL;
diff --git a/src/macros.h b/src/macros.h
index ae784d6cc1..28f43a3627 100644
--- a/src/macros.h
+++ b/src/macros.h
@@ -274,7 +274,7 @@
/* 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_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,6 +282,7 @@
# 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
diff --git a/src/os_unix.c b/src/os_unix.c
index 78063704ca..d5c5d846bb 100644
--- a/src/os_unix.c
+++ b/src/os_unix.c
@@ -4806,7 +4806,7 @@ mch_call_shell(
* round. */
for (p = buffer; p < buffer + len; p += l)
{
- l = mb_cptr2len(p);
+ l = MB_CPTR2LEN(p);
if (l == 0)
l = 1; /* NUL byte? */
else if (MB_BYTE2LEN(*p) != l)
diff --git a/src/os_win32.c b/src/os_win32.c
index d502634e3e..97a8cca9eb 100644
--- a/src/os_win32.c
+++ b/src/os_win32.c
@@ -4370,7 +4370,7 @@ dump_pipe(int options,
* round. */
for (p = buffer; p < buffer + len; p += l)
{
- l = mb_cptr2len(p);
+ l = MB_CPTR2LEN(p);
if (l == 0)
l = 1; /* NUL byte? */
else if (MB_BYTE2LEN(*p) != l)
diff --git a/src/spell.c b/src/spell.c
index 35235e04be..8d8689ba2a 100644
--- a/src/spell.c
+++ b/src/spell.c
@@ -5379,7 +5379,7 @@ suggest_trie_walk(
#ifdef FEAT_MBYTE
if (has_mbyte)
{
- n = mb_cptr2len(p);
+ n = MB_CPTR2LEN(p);
c = mb_ptr2char(p);
if (p[n] == NUL)
c2 = NUL;
@@ -5477,9 +5477,9 @@ suggest_trie_walk(
#ifdef FEAT_MBYTE
if (has_mbyte)
{
- n = mb_cptr2len(p);
+ n = MB_CPTR2LEN(p);
c = mb_ptr2char(p);
- fl = mb_cptr2len(p + n);
+ 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,10 +5596,10 @@ suggest_trie_walk(
#ifdef FEAT_MBYTE
if (has_mbyte)
{
- n = mb_cptr2len(p);
+ n = MB_CPTR2LEN(p);
c = mb_ptr2char(p);
- fl = mb_cptr2len(p + n);
- fl += mb_cptr2len(p + n + fl);
+ 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,10 +5661,10 @@ suggest_trie_walk(
#ifdef FEAT_MBYTE
if (has_mbyte)
{
- n = mb_cptr2len(p);
- n += mb_cptr2len(p + n);
+ n = MB_CPTR2LEN(p);
+ n += MB_CPTR2LEN(p + n);
c = mb_ptr2char(p + n);
- tl = mb_cptr2len(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,8 +5955,8 @@ find_keepcap_word(slang_T *slang, char_u *fword, char_u *kword)
#ifdef FEAT_MBYTE
if (has_mbyte)
{
- flen = mb_cptr2len(fword + fwordidx[depth]);
- ulen = mb_cptr2len(uword + uwordidx[depth]);
+ flen = MB_CPTR2LEN(fword + fwordidx[depth]);
+ ulen = MB_CPTR2LEN(uword + uwordidx[depth]);
}
else
#endif
diff --git a/src/testdir/test_alot_utf8.vim b/src/testdir/test_alot_utf8.vim
index 049251f9a7..539e0e1e43 100644
--- a/src/testdir/test_alot_utf8.vim
+++ b/src/testdir/test_alot_utf8.vim
@@ -8,3 +8,4 @@
source test_expr_utf8.vim
source test_matchadd_conceal_utf8.vim
source test_regexp_utf8.vim
+source test_source_utf8.vim
diff --git a/src/testdir/test_regexp_utf8.vim b/src/testdir/test_regexp_utf8.vim
index ea91829162..d2259835ca 100644
--- a/src/testdir/test_regexp_utf8.vim
+++ b/src/testdir/test_regexp_utf8.vim
@@ -92,18 +92,3 @@ func Test_classes_re2()
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
diff --git a/src/testdir/test_source_utf8.vim b/src/testdir/test_source_utf8.vim
new file mode 100644
index 0000000000..edb76fc43d
--- /dev/null
+++ b/src/testdir/test_source_utf8.vim
@@ -0,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
diff --git a/src/version.c b/src/version.c
index 539685dde0..a6c0ae3994 100644
--- a/src/version.c
+++ b/src/version.c
@@ -764,6 +764,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 2223,
+/**/
2222,
/**/
2221,