summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2020-12-24 18:39:02 +0100
committerBram Moolenaar <Bram@vim.org>2020-12-24 18:39:02 +0100
commit38455a921395a56690790c8c1d28c1c43ca04c8a (patch)
treed762d33f56f9375c80a61b1072382138e287413f
parent0261a1aeeb4ccec4ef75cc8e0685c78f5622dbf5 (diff)
downloadvim-git-38455a921395a56690790c8c1d28c1c43ca04c8a.tar.gz
patch 8.2.2207: illegal memory access if popup menu items are changedv8.2.2207
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)
-rw-r--r--src/popupmenu.c17
-rw-r--r--src/testdir/dumps/Test_popup_command_04.dump20
-rw-r--r--src/testdir/dumps/Test_popup_command_05.dump20
-rw-r--r--src/testdir/test_popup.vim28
-rw-r--r--src/version.c2
5 files changed, 83 insertions, 4 deletions
diff --git a/src/popupmenu.c b/src/popupmenu.c
index c8d305cbc..1f9840804 100644
--- a/src/popupmenu.c
+++ b/src/popupmenu.c
@@ -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
index 000000000..c14576cd8
--- /dev/null
+++ b/src/testdir/dumps/Test_popup_command_04.dump
@@ -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
index 000000000..de1c95e86
--- /dev/null
+++ b/src/testdir/dumps/Test_popup_command_05.dump
@@ -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|
diff --git a/src/testdir/test_popup.vim b/src/testdir/test_popup.vim
index 28481b3a2..9175ff1f2 100644
--- a/src/testdir/test_popup.vim
+++ b/src/testdir/test_popup.vim
@@ -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()
diff --git a/src/version.c b/src/version.c
index adba2cd4e..a5394f931 100644
--- a/src/version.c
+++ b/src/version.c
@@ -751,6 +751,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 2207,
+/**/
2206,
/**/
2205,