]> granicus.if.org Git - vim/commitdiff
patch 8.2.4139: using freed memory in expression abbreviation v8.2.4139
authorBram Moolenaar <Bram@vim.org>
Tue, 18 Jan 2022 20:30:39 +0000 (20:30 +0000)
committerBram Moolenaar <Bram@vim.org>
Tue, 18 Jan 2022 20:30:39 +0000 (20:30 +0000)
Problem:    Using freed memory if an expression abbreviation deletes the
            abbreviation.
Solution:   Do not access the pointer after evaluating the expression.

src/map.c
src/testdir/test_mapping.vim
src/version.c

index 6ad938d7ed6c9aa4bf80be541d7d4489d53f4ce3..b188e4375dcc7301306d37277d8d22f9ea10e3cc 100644 (file)
--- a/src/map.c
+++ b/src/map.c
@@ -226,7 +226,7 @@ map_add(
 #endif
        int         simplified)
 {
-    mapblock_T *mp = ALLOC_ONE(mapblock_T);
+    mapblock_T *mp = ALLOC_CLEAR_ONE(mapblock_T);
 
     if (mp == NULL)
        return FAIL;
@@ -1515,6 +1515,12 @@ check_abbr(
        }
        if (mp != NULL)
        {
+           int noremap;
+           int silent;
+#ifdef FEAT_EVAL
+           int expr;
+#endif
+
            // Found a match:
            // Insert the rest of the abbreviation in typebuf.tb_buf[].
            // This goes from end to start.
@@ -1567,8 +1573,14 @@ check_abbr(
                                        // insert the last typed char
                (void)ins_typebuf(tb, 1, 0, TRUE, mp->m_silent);
            }
+
+           // copy values here, calling eval_map_expr() may make "mp" invalid!
+           noremap = mp->m_noremap;
+           silent = mp->m_silent;
 #ifdef FEAT_EVAL
-           if (mp->m_expr)
+           expr = mp->m_expr;
+
+           if (expr)
                s = eval_map_expr(mp, c);
            else
 #endif
@@ -1576,11 +1588,11 @@ check_abbr(
            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;
 #ifdef FEAT_EVAL
-               if (mp->m_expr)
+               if (expr)
                    vim_free(s);
 #endif
            }
@@ -1590,7 +1602,7 @@ check_abbr(
            if (has_mbyte)
                len = clen;     // Delete characters instead of bytes
            while (len-- > 0)           // delete the from string
-               (void)ins_typebuf(tb, 1, 0, TRUE, mp->m_silent);
+               (void)ins_typebuf(tb, 1, 0, TRUE, silent);
            return TRUE;
        }
     }
@@ -1601,6 +1613,7 @@ check_abbr(
 /*
  * 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.
  */
     char_u *
 eval_map_expr(
index b170b580dc981dcf470dd52011c36393f7d2ca05..a556362ba5b26d49c83a91b9bdbea4abfb992e2a 100644 (file)
@@ -704,6 +704,11 @@ func Test_mapcomplete()
   mapclear
 endfunc
 
+func GetAbbrText()
+  unabbr hola
+  return 'hello'
+endfunc
+
 " Test for <expr> in abbreviation
 func Test_expr_abbr()
   new
@@ -719,7 +724,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
index 6198d410609209892ec39c46aa8b2c4bdf400a98..07d5b81f857fcdbde7a2d217817741176ef47261 100644 (file)
@@ -750,6 +750,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    4139,
 /**/
     4138,
 /**/