Skip to content

Commit f0135d9

Browse files
authored
Merge pull request neovim#18491 from zeertzjq/vim-8.2.4924
vim-patch:8.2.4924: maparg() may return a string that cannot be reused
2 parents 41ce7b0 + db506d9 commit f0135d9

File tree

5 files changed

+62
-18
lines changed

5 files changed

+62
-18
lines changed

src/nvim/message.c

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1618,6 +1618,10 @@ int msg_outtrans_special(const char_u *strstart, bool from, int maxlen)
16181618
} else {
16191619
text = str2special((const char **)&str, from, false);
16201620
}
1621+
if (text[0] != NUL && text[1] == NUL) {
1622+
// single-byte character or illegal byte
1623+
text = (char *)transchar_byte((uint8_t)text[0]);
1624+
}
16211625
const int len = vim_strsize((char_u *)text);
16221626
if (maxlen > 0 && retval + len >= maxlen) {
16231627
break;
@@ -1666,6 +1670,7 @@ char *str2special_save(const char *const str, const bool replace_spaces, const b
16661670
/// @return Converted key code, in a static buffer. Buffer is always one and the
16671671
/// same, so save converted string somewhere before running str2special
16681672
/// for the second time.
1673+
/// On illegal byte return a string with only that byte.
16691674
const char *str2special(const char **const sp, const bool replace_spaces, const bool replace_lt)
16701675
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_RET
16711676
{
@@ -1699,32 +1704,26 @@ const char *str2special(const char **const sp, const bool replace_spaces, const
16991704
}
17001705
}
17011706

1702-
if (!IS_SPECIAL(c)) {
1707+
if (!IS_SPECIAL(c) && MB_BYTE2LEN(c) > 1) {
17031708
*sp = str;
17041709
// Try to un-escape a multi-byte character after modifiers.
17051710
const char *p = mb_unescape(sp);
1706-
1707-
if (p == NULL) {
1708-
const int len = utf_ptr2len(str);
1709-
// Check for an illegal byte.
1710-
if (MB_BYTE2LEN((uint8_t)(*str)) > len) {
1711-
transchar_nonprint(curbuf, (char_u *)buf, c);
1712-
*sp = str + 1;
1713-
return buf;
1714-
}
1715-
*sp = str + len;
1716-
p = str;
1711+
if (p != NULL) {
1712+
// Since 'special' is true the multi-byte character 'c' will be
1713+
// processed by get_special_key_name().
1714+
c = utf_ptr2char(p);
1715+
} else {
1716+
// illegal byte
1717+
*sp = str + 1;
17171718
}
1718-
// Since 'special' is true the multi-byte character 'c' will be
1719-
// processed by get_special_key_name().
1720-
c = utf_ptr2char(p);
17211719
} else {
1720+
// single-byte character or illegal byte
17221721
*sp = str + 1;
17231722
}
17241723

1725-
// Make unprintable characters in <> form, also <M-Space> and <Tab>.
1724+
// Make special keys and C0 control characters in <> form, also <M-Space>.
17261725
if (special
1727-
|| char2cells(c) > 1
1726+
|| c < ' '
17281727
|| (replace_spaces && c == ' ')
17291728
|| (replace_lt && c == '<')) {
17301729
return (const char *)get_special_key_name(c, modifiers);

src/nvim/option.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4980,7 +4980,11 @@ int get_option_value(const char *name, long *numval, char **stringval, int opt_f
49804980
return -2;
49814981
}
49824982
if (stringval != NULL) {
4983-
*stringval = xstrdup(*(char **)varp);
4983+
if ((char_u **)varp == &p_pt) { // 'pastetoggle'
4984+
*stringval = str2special_save(*(char **)(varp), false, false);
4985+
} else {
4986+
*stringval = xstrdup(*(char **)(varp));
4987+
}
49844988
}
49854989
return 0;
49864990
}

src/nvim/testdir/test_maparg.vim

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,20 @@ function Test_maparg()
4242
map abc y<S-char-114>y
4343
call assert_equal("yRy", maparg('abc'))
4444

45+
" character with K_SPECIAL byte
46+
nmap abc
47+
call assert_equal('', maparg('abc'))
48+
49+
" modified character with K_SPECIAL byte
50+
nmap abc <M-…>
51+
call assert_equal('<M-…>', maparg('abc'))
52+
53+
" illegal bytes
54+
let str = ":\x7f:\x80:\x90:\xd0:"
55+
exe 'nmap abc ' .. str
56+
call assert_equal(str, maparg('abc'))
57+
unlet str
58+
4559
omap { w
4660
let d = maparg('{', 'o', 0, 1)
4761
call assert_equal(['{', 'w', 'o'], [d.lhs, d.rhs, d.mode])

src/nvim/testdir/test_mapping.vim

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,13 @@ func Test_list_mappings()
488488
call assert_equal(['n <M-…> foo'],
489489
\ execute('nmap <M-…>')->trim()->split("\n"))
490490

491+
" illegal bytes
492+
let str = ":\x7f:\x80:\x90:\xd0:"
493+
exe 'nmap foo ' .. str
494+
call assert_equal(['n foo ' .. strtrans(str)],
495+
\ execute('nmap foo')->trim()->split("\n"))
496+
unlet str
497+
491498
" map to CTRL-V
492499
exe "nmap ,k \<C-V>"
493500
call assert_equal(['n ,k <Nop>'],

src/nvim/testdir/test_options.vim

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,26 @@ func Test_isfname()
3131
set isfname&
3232
endfunc
3333

34+
" Test for getting the value of 'pastetoggle'
35+
func Test_pastetoggle()
36+
" character with K_SPECIAL byte
37+
let &pastetoggle = ''
38+
call assert_equal('', &pastetoggle)
39+
call assert_equal("\n pastetoggle=…", execute('set pastetoggle?'))
40+
41+
" modified character with K_SPECIAL byte
42+
let &pastetoggle = '<M-…>'
43+
call assert_equal('<M-…>', &pastetoggle)
44+
call assert_equal("\n pastetoggle=<M-…>", execute('set pastetoggle?'))
45+
46+
" illegal bytes
47+
let str = ":\x7f:\x80:\x90:\xd0:"
48+
let &pastetoggle = str
49+
call assert_equal(str, &pastetoggle)
50+
call assert_equal("\n pastetoggle=" .. strtrans(str), execute('set pastetoggle?'))
51+
unlet str
52+
endfunc
53+
3454
func Test_wildchar()
3555
" Empty 'wildchar' used to access invalid memory.
3656
call assert_fails('set wildchar=', 'E521:')

0 commit comments

Comments
 (0)