fix(ui2): bogus "'replacement string' item" message #42650

Problem:
UI event handlers may clobber `IObuff` while the caller is using it.
With ui2 `targets='msg'`, `i_CTRL-O :edit` shows "'replacement string'
item" instead of the file info, because `check_string_array()` writes
`IObuff` on every `nvim_buf_set_lines()`.

Solution:
- Save and restore `IObuff` around UI event handlers. This is 1KB, but
  negligible vs the other work that UI handlers do (msgpack, Lua calls).
- `check_string_array()`: don't use `IObuff`.
This commit is contained in:
Justin M. Keyes authored and GitHub committed 2026-11-02 06:57:23 -05:00
1 parent 13f4c205e1
commit 124a28de97
3 files changed
+23 -5

No files matched your search

+4 -5
View File
@@ -1,12 +1,10 @@
#include <inttypes.h>
#include <stdio.h>
#include <string.h>
#include "nvim/api/private/defs.h"
#include "nvim/api/private/helpers.h"
#include "nvim/api/private/validate.h"
#include "nvim/ascii_defs.h"
#include "nvim/globals.h"
/// Creates "Invalid …" message and sets it on `err`.
void api_err_invalid(Error *err, const char *name, const char *val_s, int64_t val_n, bool quote_val)
@@ -84,11 +82,12 @@ void api_err_conflict(Error *err, const char *name, const char *name2)
bool check_string_array(Array arr, char *name, bool disallow_nl, Error *err)
{
snprintf(IObuff, sizeof(IObuff), "'%s' item", name);
for (size_t i = 0; i < arr.size; i++) {
VALIDATE_T(IObuff, kObjectTypeString, arr.items[i].type, {
if (arr.items[i].type != kObjectTypeString) {
api_set_error(err, kErrorTypeValidation, "Invalid '%s' item: expected String, got %s", name,
api_typename(arr.items[i].type));
return false;
});
}
// Disallow newlines in the middle of the line.
if (disallow_nl) {
const String l = arr.items[i].data.string;
+4
View File
@@ -797,6 +797,9 @@ void ui_call_event(char *name, Array args)
int save_textlock = textlock;
expr_map_lock = 0;
textlock = 0;
// Caller may still be using `IObuff`, e.g. as the message being shown.
char save_iobuff[IOSIZE];
memcpy(save_iobuff, IObuff, IOSIZE);
bool handled = false;
bool fast = msg_ext_fast && strcmp("msg_show", name) == 0;
@@ -818,6 +821,7 @@ void ui_call_event(char *name, Array args)
expr_map_lock = save_expr_map_lock;
textlock = save_textlock;
memcpy(IObuff, save_iobuff, IOSIZE);
ctx_load(&ctx, kCtxCount, 0);
ctx_free(&ctx);
+15
View File
@@ -1196,6 +1196,21 @@ describe('messages2', function()
end)
feed('2gm')
t.eq(2, exec_lua('return _G.count'))
-- Handler does not clobber the file info message, which is repeated after `i_CTRL-O`.
finally(function()
os.remove('Xfile')
end)
t.write_file('Xfile', '')
command('set messagesopt& shortmess-=F | edit Xfile')
feed('i<C-o>:edit<CR>')
screen:expect([[
^ |
{1:~ }|*10
{1:~ }{4:"Xfile" "Xfile" }|
{1:~ }{4:"Xfile" 0L, 0B(1)}|
{5:-- INSERT --} |
]])
end)
it('configured targets per kind', function()