1
1
mirror of https://github.com/mawww/kakoune.git synced 2024-11-27 12:16:22 +03:00

Fix <c-r> use-after-free InsertCompletionHide touches used register

Before performing the insertion, InsertCompleter::insert calls
try_accept() to accept any selected completion candidate.  If there
is one, we fire InsertCompletionHide. If that one modifies the register
used by <c-r>, the inserted StringViews will be dangling.

Fix this by running try_insert first, and read from the register later.
Note that we call try_accept() twice but that's fine.

It would probably make more sense to copy the register before calling
insert() but I don't think it matters.

Closes #5220
This commit is contained in:
Johannes Altmanninger 2024-08-28 15:47:27 +02:00 committed by Maxime Coste
parent 9275d965a6
commit 6e5bc9dd6c
6 changed files with 28 additions and 1 deletions

View File

@ -15,6 +15,7 @@
#include "window.hh" #include "window.hh"
#include "word_db.hh" #include "word_db.hh"
#include <concepts>
#include <utility> #include <utility>
#include <limits> #include <limits>
@ -1310,7 +1311,7 @@ public:
auto cp = key.codepoint(); auto cp = key.codepoint();
if (not cp or key == Key::Escape) if (not cp or key == Key::Escape)
return; return;
insert(RegisterManager::instance()[*cp].get(context())); insert([&] { return RegisterManager::instance()[*cp].get(context()); });
}, "enter register name", register_doc.str()); }, "enter register name", register_doc.str());
update_completions = false; update_completions = false;
} }
@ -1430,6 +1431,13 @@ private:
}, false); }, false);
} }
template<std::invocable Func>
void insert(Func&& lazy_strings)
{
m_completer.try_accept();
insert(std::forward<Func>(lazy_strings)());
}
void insert(Codepoint key) void insert(Codepoint key)
{ {
String str{key}; String str{key};

View File

@ -0,0 +1 @@

View File

@ -0,0 +1 @@
echo

View File

@ -0,0 +1,2 @@
echofoobar
echo

View File

@ -0,0 +1,8 @@
set-option global autocomplete insert
hook global InsertCompletionHide .+ %{
evaluate-commands -draft -save-regs '"' %{
select %val{hook_param}
set-register dquote foo bar
execute-keys <a-p>
}
}

View File

@ -0,0 +1,7 @@
ui_out -until '{ "jsonrpc": "2.0", "method": "refresh", "params": [true] }'
ui_in '{ "jsonrpc": "2.0", "method": "keys", "params": [ "Oe" ] }'
ui_out -until '{ "jsonrpc": "2.0", "method": "menu_show", "params": [[[{ "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": "echo" }, { "face": { "fg": "default", "bg": "default", "underline": "default", "attributes": [] }, "contents": " " }, { "face": { "fg": "cyan", "bg": "default", "underline": "default", "attributes": [] }, "contents": "out" }]], { "line": 0, "column": 0 }, { "fg": "white", "bg": "blue", "underline": "default", "attributes": [] }, { "fg": "blue", "bg": "white", "underline": "default", "attributes": [] }, "inline"] }'
ui_in '{ "jsonrpc": "2.0", "method": "keys", "params": [ "<c-n>" ] }'
ui_out -until '{ "jsonrpc": "2.0", "method": "menu_select", "params": [1] }'
ui_in '{ "jsonrpc": "2.0", "method": "keys", "params": [ "<c-r>\"" ] }'
ui_out -until '{ "jsonrpc": "2.0", "method": "menu_hide", "params": [] }'