Skip to content

Commit

Permalink
patch 8.2.4924: maparg() may return a string that cannot be reused
Browse files Browse the repository at this point in the history
Problem:    maparg() may return a string that cannot be reused.
Solution:   use msg_outtrans_special() instead of str2special().
            (closes #10384)
  • Loading branch information
zeertzjq authored and brammool committed May 9, 2022
1 parent 1948430 commit 0519ce0
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 21 deletions.
36 changes: 15 additions & 21 deletions src/message.c
Expand Up @@ -1721,6 +1721,9 @@ msg_outtrans_special(
}
else
text = (char *)str2special(&str, from);
if (text[0] != NUL && text[1] == NUL)
// single-byte character or illegal byte
text = (char *)transchar_byte((char_u)text[0]);
len = vim_strsize((char_u *)text);
if (maxlen > 0 && retval + len >= maxlen)
break;
Expand Down Expand Up @@ -1755,6 +1758,7 @@ str2special_save(

/*
* Return the printable string for the key codes at "*sp".
* On illegal byte return a string with only that byte.
* Used for translating the lhs or rhs of a mapping to printable chars.
* Advances "sp" to the next code.
*/
Expand Down Expand Up @@ -1798,38 +1802,28 @@ str2special(
special = TRUE;
}

if (has_mbyte && !IS_SPECIAL(c))
if (has_mbyte && !IS_SPECIAL(c) && MB_BYTE2LEN(c) > 1)
{
char_u *p;

*sp = str;
// Try to un-escape a multi-byte character after modifiers.
p = mb_unescape(sp);

if (p == NULL)
{
int len = (*mb_ptr2len)(str);

// Check for an illegal byte.
if (MB_BYTE2LEN(*str) > len)
{
transchar_nonprint(curbuf, buf, c);
*sp = str + 1;
return buf;
}
*sp = str + len;
p = str;
}
// Since 'special' is TRUE the multi-byte character 'c' will be
// processed by get_special_key_name()
c = (*mb_ptr2char)(p);
if (p != NULL)
// Since 'special' is TRUE the multi-byte character 'c' will be
// processed by get_special_key_name()
c = (*mb_ptr2char)(p);
else
// illegal byte
*sp = str + 1;
}
else
// single-byte character or illegal byte
*sp = str + 1;

// Make unprintable characters in <> form, also <M-Space> and <Tab>.
// Make special keys and C0 control characters in <> form, also <M-Space>.
// Use <Space> only for lhs of a mapping.
if (special || char2cells(c) > 1 || (from && c == ' '))
if (special || c < ' ' || (from && c == ' '))
return get_special_key_name(c, modifiers);
buf[0] = c;
buf[1] = NUL;
Expand Down
2 changes: 2 additions & 0 deletions src/option.c
Expand Up @@ -4017,6 +4017,8 @@ get_option_value(
if ((char_u **)varp == &curbuf->b_p_key
&& **(char_u **)(varp) != NUL)
*stringval = vim_strsave((char_u *)"*****");
else if ((char_u **)varp == &p_pt) // 'pastetoggle'
*stringval = str2special_save(*(char_u **)(varp), FALSE);
else
#endif
*stringval = vim_strsave(*(char_u **)(varp));
Expand Down
14 changes: 14 additions & 0 deletions src/testdir/test_map_functions.vim
Expand Up @@ -58,6 +58,20 @@ func Test_maparg()
map abc y<S-char-114>y
call assert_equal("yRy", maparg('abc'))

" character with K_SPECIAL byte
nmap abc
call assert_equal('', maparg('abc'))

" modified character with K_SPECIAL byte
nmap abc <M-…>
call assert_equal('<M-…>', maparg('abc'))

" illegal bytes
let str = ":\x7f:\x80:\x90:\xd0:"
exe 'nmap abc ' .. str
call assert_equal(str, maparg('abc'))
unlet str

omap { w
let d = maparg('{', 'o', 0, 1)
call assert_equal(['{', 'w', 'o'], [d.lhs, d.rhs, d.mode])
Expand Down
7 changes: 7 additions & 0 deletions src/testdir/test_mapping.vim
Expand Up @@ -502,6 +502,13 @@ func Test_list_mappings()
call assert_equal(['n <M-…> foo'],
\ execute('nmap <M-…>')->trim()->split("\n"))

" illegal bytes
let str = ":\x7f:\x80:\x90:\xd0:"
exe 'nmap foo ' .. str
call assert_equal(['n foo ' .. strtrans(str)],
\ execute('nmap foo')->trim()->split("\n"))
unlet str

" map to CTRL-V
exe "nmap ,k \<C-V>"
call assert_equal(['n ,k <Nop>'],
Expand Down
20 changes: 20 additions & 0 deletions src/testdir/test_options.vim
Expand Up @@ -48,6 +48,26 @@ func Test_isfname()
set isfname&
endfunc

" Test for getting the value of 'pastetoggle'
func Test_pastetoggle()
" character with K_SPECIAL byte
let &pastetoggle = ''
call assert_equal('', &pastetoggle)
call assert_equal("\n pastetoggle=…", execute('set pastetoggle?'))

" modified character with K_SPECIAL byte
let &pastetoggle = '<M-…>'
call assert_equal('<M-…>', &pastetoggle)
call assert_equal("\n pastetoggle=<M-…>", execute('set pastetoggle?'))

" illegal bytes
let str = ":\x7f:\x80:\x90:\xd0:"
let &pastetoggle = str
call assert_equal(str, &pastetoggle)
call assert_equal("\n pastetoggle=" .. strtrans(str), execute('set pastetoggle?'))
unlet str
endfunc

func Test_wildchar()
" Empty 'wildchar' used to access invalid memory.
call assert_fails('set wildchar=', 'E521:')
Expand Down
2 changes: 2 additions & 0 deletions src/version.c
Expand Up @@ -746,6 +746,8 @@ static char *(features[]) =

static int included_patches[] =
{ /* Add new patch number below this line */
/**/
4924,
/**/
4923,
/**/
Expand Down

0 comments on commit 0519ce0

Please sign in to comment.