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
This commit is contained in:
Johannes Altmanninger 2024-04-21 20:18:28 +02:00 committed by Maxime Coste
parent ab2ecf423e
commit aad0c7cef8
5 changed files with 10 additions and 2 deletions

View File

@ -108,7 +108,7 @@ public:
HookManager& hooks() const { return scope().hooks(); } HookManager& hooks() const { return scope().hooks(); }
KeymapManager& keymaps() const { return scope().keymaps(); } KeymapManager& keymaps() const { return scope().keymaps(); }
AliasRegistry& aliases() const { return scope().aliases(); } 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; void print_status(DisplayLine status) const;

View File

@ -657,7 +657,8 @@ public:
: InputMode(input_handler), m_callback(std::move(callback)), m_completer(std::move(completer)), : InputMode(input_handler), m_callback(std::move(callback)), m_completer(std::move(completer)),
m_prompt(prompt.str()), m_prompt_face(face), m_prompt(prompt.str()), m_prompt_face(face),
m_empty_text{std::move(emptystr)}, 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_was_interactive{not context().noninteractive()},
m_history{RegisterManager::instance()[history_register]}, m_history{RegisterManager::instance()[history_register]},
m_current_history{-1}, m_current_history{-1},

View File

@ -0,0 +1 @@

View File

@ -0,0 +1 @@

View File

@ -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