]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 8.2.2207: illegal memory access if popup menu items are changed v8.2.2207
authorBram Moolenaar <Bram@vim.org>
Thu, 24 Dec 2020 17:39:02 +0000 (18:39 +0100)
committerBram Moolenaar <Bram@vim.org>
Thu, 24 Dec 2020 17:39:02 +0000 (18:39 +0100)
Problem:    Illegal memory access if popup menu items are changed while the
            menu is visible. (Tomáš Janoušek)
Solution:   Make a copy of the text. (closes #7537)

src/popupmenu.c
src/testdir/dumps/Test_popup_command_04.dump [new file with mode: 0644]
src/testdir/dumps/Test_popup_command_05.dump [new file with mode: 0644]
src/testdir/test_popup.vim
src/version.c

index c8d305cbcbd2b3a4cbda7b4b2eae110fea14193b..1f9840804027d63ec520e260ae5fb3e25e198f01 100644 (file)
@@ -1458,10 +1458,21 @@ pum_show_popupmenu(vimmenu_T *menu)
        return;
 
     FOR_ALL_CHILD_MENUS(menu, mp)
+    {
+       char_u *s = NULL;
+
+       // Make a copy of the text, the menu may be redefined in a callback.
        if (menu_is_separator(mp->dname))
-           array[idx++].pum_text = (char_u *)"";
+           s = (char_u *)"";
        else if (mp->modes & mp->enabled & mode)
-           array[idx++].pum_text = mp->dname;
+           s = mp->dname;
+       if (s != NULL)
+       {
+           s = vim_strsave(s);
+           if (s != NULL)
+               array[idx++].pum_text = s;
+       }
+    }
 
     pum_array = array;
     pum_compute_size();
@@ -1542,6 +1553,8 @@ pum_show_popupmenu(vimmenu_T *menu)
        }
     }
 
+    for (idx = 0; idx < pum_size; ++idx)
+       vim_free(array[idx].pum_text);
     vim_free(array);
     pum_undisplay();
 # ifdef FEAT_BEVAL_TERM
diff --git a/src/testdir/dumps/Test_popup_command_04.dump b/src/testdir/dumps/Test_popup_command_04.dump
new file mode 100644 (file)
index 0000000..c14576c
--- /dev/null
@@ -0,0 +1,20 @@
+|o+0&#ffffff0|n|e| |t|w|o| |t|h|r|e@1| |f|o|u|r| |f|i|v|e| @51
+|a|n|d| |o|n|e| |t|w|o| |X|t|h|r|e@1| |f|o|u|r| |f|i|v|e| @46
+|o|n|e| |m|o|r|e| |t|w| +0#0000001#ffd7ff255|U|n|d|o| @12| +0#0000000#ffffff0@45
+|~+0#4040ff13&| @9| +0#0000001#ffd7ff255@17| +0#4040ff13#ffffff0@45
+|~| @9| +0#0000001#ffd7ff255|P|a|s|t|e| @11| +0#4040ff13#ffffff0@45
+|~| @9| +0#0000001#ffd7ff255@17| +0#4040ff13#ffffff0@45
+|~| @9| +0#0000001#ffd7ff255|S|e|l|e|c|t| |W|o|r|d| @5| +0#4040ff13#ffffff0@45
+|~| @9| +0#0000001#ffd7ff255|S|e|l|e|c|t| |S|e|n|t|e|n|c|e| @1| +0#4040ff13#ffffff0@45
+|~| @9| +0#0000001#ffd7ff255|S|e|l|e|c|t| |P|a|r|a|g|r|a|p|h| | +0#4040ff13#ffffff0@45
+|~| @9| +0#0000001#ffd7ff255|S|e|l|e|c|t| |L|i|n|e| @5| +0#4040ff13#ffffff0@45
+|~| @9| +0#0000001#ffd7ff255|S|e|l|e|c|t| |B|l|o|c|k| @4| +0#4040ff13#ffffff0@45
+|~| @9| +0#0000001#ffd7ff255|S|e|l|e|c|t| |A|l@1| @6| +0#4040ff13#ffffff0@45
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|c+0#0000000&|h|a|n|g|e|d> @67
diff --git a/src/testdir/dumps/Test_popup_command_05.dump b/src/testdir/dumps/Test_popup_command_05.dump
new file mode 100644 (file)
index 0000000..de1c95e
--- /dev/null
@@ -0,0 +1,20 @@
+|o+0&#ffffff0|n|e| |t|w|o| |t|h|r|e@1| |f|o|u|r| |f|i|v|e| @51
+|a|n|d| |o|n|e| |t|w|o| >X|t|h|r|e@1| |f|o|u|r| |f|i|v|e| @46
+|o|n|e| |m|o|r|e| |t|w|o| |t|h|r|e@1| |f|o|u|r| |f|i|v|e| @46
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|p+0#0000000&|a|s|t|e|d| @50|2|,|1|3| @9|A|l@1| 
index 28481b3a2865de434bfde4d298b44b4e323884e7..9175ff1f26d6c6f33d7fea70e2406bfc601c0555 100644 (file)
@@ -859,18 +859,30 @@ func Test_popup_command()
   call assert_fails('popup Foo', 'E337:')
   unmenu Test.Foo
 
+  let script =<< trim END
+    func StartTimer()
+      call timer_start(100, {-> ChangeMenu()})
+    endfunc
+    func ChangeMenu()
+      nunmenu PopUp.&Paste
+      nnoremenu 1.40 PopUp.&Paste :echomsg "pasted"<CR>
+      echomsg 'changed'
+    endfunc
+  END
+  call writefile(script, 'XtimerScript')
+
   let lines =<< trim END
        one two three four five
        and one two Xthree four five
        one more two three four five
   END
   call writefile(lines, 'Xtest')
-  let buf = RunVimInTerminal('Xtest', {})
+  let buf = RunVimInTerminal('-S XtimerScript Xtest', {})
   call term_sendkeys(buf, ":source $VIMRUNTIME/menu.vim\<CR>")
   call term_sendkeys(buf, "/X\<CR>:popup PopUp\<CR>")
   call VerifyScreenDump(buf, 'Test_popup_command_01', {})
 
-  " Select a word
+  " go to the Paste entry in the menu
   call term_sendkeys(buf, "jj")
   call VerifyScreenDump(buf, 'Test_popup_command_02', {})
 
@@ -879,8 +891,20 @@ func Test_popup_command()
   call VerifyScreenDump(buf, 'Test_popup_command_03', {})
 
   call term_sendkeys(buf, "\<Esc>")
+
+  " Set a timer to change a menu entry while it's displayed.  The text should
+  " not change but the command does.  Making the screendump also verifies that
+  " "changed" shows up, which means the timer triggered
+  call term_sendkeys(buf, "/X\<CR>:call StartTimer() | popup PopUp\<CR>")
+  call VerifyScreenDump(buf, 'Test_popup_command_04', {})
+
+  " Select the Paste entry, executes the changed menu item.
+  call term_sendkeys(buf, "jj\<CR>")
+  call VerifyScreenDump(buf, 'Test_popup_command_05', {})
+
   call StopVimInTerminal(buf)
   call delete('Xtest')
+  call delete('XtimerScript')
 endfunc
 
 func Test_popup_complete_backwards()
index adba2cd4e2a68375fb6e59f35e4f0fca475e8ea6..a5394f931e8eba18a097024f8e0ba37a66712725 100644 (file)
@@ -750,6 +750,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    2207,
 /**/
     2206,
 /**/