summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohannes Altmanninger <aclopte@gmail.com>2024-04-21 20:18:28 +0200
committerMaxime Coste <mawww@kakoune.org>2024-04-27 16:29:57 +1000
commitaad0c7cef84990595cdb649b679063da9e8cb581 (patch)
tree6700854f0f85a92a529203d1f95eb68f943ee52f
parentab2ecf423e49a9797601379bbc5141d7301ac2fb (diff)
Don't capture local-scoped faces in prompt
ASan shows that we resolve a face spec owned by a freed stack variable. ================================================================= ==2263300==ERROR: AddressSanitizer: stack-use-after-return on address 0x7a9316c33918 at pc 0x633ea421d8ea bp 0x7ffca001e980 sp 0x7ffca001e970 READ of size 8 at 0x7a9316c33918 thread T0 ... #6 0x633ea421d8e9 in Kakoune::FaceRegistry::resolve_spec(Kakoune::FaceSpec const&) const src/face_registry.cc:128 ... Address 0x7a9316c33918 is located in stack of thread T0 at offset 2328 in frame #0 0x633ea427a095 in operator() src/commands.cc:2267 This frame has 26 object(s): [32, 36) '<unknown>' ... [544, 560) 'disable_hooks' (line 2269) ... [928, 2432) 'local_scope' (line 2271) <== Memory access at offset 2328 is inside this variable
-rw-r--r--src/context.hh2
-rw-r--r--src/input_handler.cc3
-rw-r--r--test/regression/0-eval-creates-prompt/cmd1
-rw-r--r--test/regression/0-eval-creates-prompt/in1
-rw-r--r--test/regression/0-eval-creates-prompt/script5
5 files changed, 10 insertions, 2 deletions
diff --git a/src/context.hh b/src/context.hh
index 7ff4166e..fb45fc2d 100644
--- a/src/context.hh
+++ b/src/context.hh
@@ -108,7 +108,7 @@ public:
HookManager& hooks() const { return scope().hooks(); }
KeymapManager& keymaps() const { return scope().keymaps(); }
AliasRegistry& aliases() const { return scope().aliases(); }
- FaceRegistry& faces() const { return scope().faces(); }
+ FaceRegistry& faces(bool allow_local = true) const { return scope(allow_local).faces(); }
void print_status(DisplayLine status) const;
diff --git a/src/input_handler.cc b/src/input_handler.cc
index e11740c7..99fb684e 100644
--- a/src/input_handler.cc
+++ b/src/input_handler.cc
@@ -657,7 +657,8 @@ public:
: InputMode(input_handler), m_callback(std::move(callback)), m_completer(std::move(completer)),
m_prompt(prompt.str()), m_prompt_face(face),
m_empty_text{std::move(emptystr)},
- m_line_editor{context().faces()}, m_flags(flags),
+ // This prompt may outlive local scopes so ignore local faces.
+ m_line_editor{context().faces(false)}, m_flags(flags),
m_was_interactive{not context().noninteractive()},
m_history{RegisterManager::instance()[history_register]},
m_current_history{-1},
diff --git a/test/regression/0-eval-creates-prompt/cmd b/test/regression/0-eval-creates-prompt/cmd
new file mode 100644
index 00000000..8b137891
--- /dev/null
+++ b/test/regression/0-eval-creates-prompt/cmd
@@ -0,0 +1 @@
+
diff --git a/test/regression/0-eval-creates-prompt/in b/test/regression/0-eval-creates-prompt/in
new file mode 100644
index 00000000..8b137891
--- /dev/null
+++ b/test/regression/0-eval-creates-prompt/in
@@ -0,0 +1 @@
+
diff --git a/test/regression/0-eval-creates-prompt/script b/test/regression/0-eval-creates-prompt/script
new file mode 100644
index 00000000..c9455f5e
--- /dev/null
+++ b/test/regression/0-eval-creates-prompt/script
@@ -0,0 +1,5 @@
+ui_out -ignore 7
+ui_in '{ "jsonrpc": "2.0", "method": "keys", "params": [ ":eval %{ exec %{:echo -} }<ret>" ] }'
+ui_out -ignore 5
+ui_in '{ "jsonrpc": "2.0", "method": "keys", "params": [ "markup 123<ret>" ] }'
+ui_out -until-grep '"method": "draw_status", .* "contents": "123"' >/dev/null