mirror of
https://github.com/neovim/neovim.git
synced 2025-09-05 19:08:15 +00:00
vim-patch:8.2.4139: using freed memory in expression abbreviation (#21522)
Problem: Using freed memory if an expression abbreviation deletes the
abbreviation.
Solution: Do not access the pointer after evaluating the expression.
94075b2b0e
Co-authored-by: Bram Moolenaar <Bram@vim.org>
This commit is contained in:
@@ -2191,12 +2191,12 @@ static int handle_mapping(int *keylenp, const bool *timedout, int *mapdepth)
|
||||
// Copy the values from *mp that are used, because evaluating the
|
||||
// expression may invoke a function that redefines the mapping, thereby
|
||||
// making *mp invalid.
|
||||
char save_m_expr = mp->m_expr;
|
||||
int save_m_noremap = mp->m_noremap;
|
||||
char save_m_silent = mp->m_silent;
|
||||
const bool save_m_expr = mp->m_expr;
|
||||
const int save_m_noremap = mp->m_noremap;
|
||||
const bool save_m_silent = mp->m_silent;
|
||||
char *save_m_keys = NULL; // only saved when needed
|
||||
char *save_m_str = NULL; // only saved when needed
|
||||
LuaRef save_m_luaref = mp->m_luaref;
|
||||
const LuaRef save_m_luaref = mp->m_luaref;
|
||||
|
||||
// Handle ":map <expr>": evaluate the {rhs} as an
|
||||
// expression. Also save and restore the command line
|
||||
|
@@ -1517,17 +1517,23 @@ bool check_abbr(int c, char *ptr, int col, int mincol)
|
||||
// insert the last typed char
|
||||
(void)ins_typebuf((char *)tb, 1, 0, true, mp->m_silent);
|
||||
}
|
||||
if (mp->m_expr) {
|
||||
|
||||
// copy values here, calling eval_map_expr() may make "mp" invalid!
|
||||
const int noremap = mp->m_noremap;
|
||||
const bool silent = mp->m_silent;
|
||||
const bool expr = mp->m_expr;
|
||||
|
||||
if (expr) {
|
||||
s = eval_map_expr(mp, c);
|
||||
} else {
|
||||
s = mp->m_str;
|
||||
}
|
||||
if (s != NULL) {
|
||||
// insert the to string
|
||||
(void)ins_typebuf(s, mp->m_noremap, 0, true, mp->m_silent);
|
||||
(void)ins_typebuf(s, noremap, 0, true, silent);
|
||||
// no abbrev. for these chars
|
||||
typebuf.tb_no_abbr_cnt += (int)strlen(s) + j + 1;
|
||||
if (mp->m_expr) {
|
||||
if (expr) {
|
||||
xfree(s);
|
||||
}
|
||||
}
|
||||
@@ -1536,7 +1542,7 @@ bool check_abbr(int c, char *ptr, int col, int mincol)
|
||||
tb[1] = NUL;
|
||||
len = clen; // Delete characters instead of bytes
|
||||
while (len-- > 0) { // delete the from string
|
||||
(void)ins_typebuf((char *)tb, 1, 0, true, mp->m_silent);
|
||||
(void)ins_typebuf((char *)tb, 1, 0, true, silent);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -1546,6 +1552,7 @@ bool check_abbr(int c, char *ptr, int col, int mincol)
|
||||
|
||||
/// Evaluate the RHS of a mapping or abbreviations and take care of escaping
|
||||
/// special characters.
|
||||
/// Careful: after this "mp" will be invalid if the mapping was deleted.
|
||||
///
|
||||
/// @param c NUL or typed character for abbreviation
|
||||
char *eval_map_expr(mapblock_T *mp, int c)
|
||||
@@ -1560,6 +1567,8 @@ char *eval_map_expr(mapblock_T *mp, int c)
|
||||
vim_unescape_ks((char_u *)expr);
|
||||
}
|
||||
|
||||
const bool replace_keycodes = mp->m_replace_keycodes;
|
||||
|
||||
// Forbid changing text or using ":normal" to avoid most of the bad side
|
||||
// effects. Also restore the cursor position.
|
||||
textlock++;
|
||||
@@ -1596,7 +1605,7 @@ char *eval_map_expr(mapblock_T *mp, int c)
|
||||
|
||||
char *res = NULL;
|
||||
|
||||
if (mp->m_replace_keycodes) {
|
||||
if (replace_keycodes) {
|
||||
replace_termcodes(p, strlen(p), &res, REPTERM_DO_LT, NULL, CPO_TO_CPO_FLAGS);
|
||||
} else {
|
||||
// Escape K_SPECIAL in the result to be able to use the string as typeahead.
|
||||
|
@@ -767,6 +767,11 @@ func Test_mapcomplete()
|
||||
mapclear
|
||||
endfunc
|
||||
|
||||
func GetAbbrText()
|
||||
unabbr hola
|
||||
return 'hello'
|
||||
endfunc
|
||||
|
||||
" Test for <expr> in abbreviation
|
||||
func Test_expr_abbr()
|
||||
new
|
||||
@@ -782,7 +787,14 @@ func Test_expr_abbr()
|
||||
call assert_equal('', getline(1))
|
||||
unabbr <expr> hte
|
||||
|
||||
close!
|
||||
" evaluating the expression deletes the abbreviation
|
||||
abbr <expr> hola GetAbbrText()
|
||||
call assert_equal('GetAbbrText()', maparg('hola', 'i', '1'))
|
||||
call feedkeys("ahola \<Esc>", 'xt')
|
||||
call assert_equal('hello ', getline('.'))
|
||||
call assert_equal('', maparg('hola', 'i', '1'))
|
||||
|
||||
bwipe!
|
||||
endfunc
|
||||
|
||||
" Test for storing mappings in different modes in a vimrc file
|
||||
|
Reference in New Issue
Block a user