diff options
| author | bfredl <bjorn.linse@gmail.com> | 2026-09-07 13:39:56 +0200 |
|---|---|---|
| committer | bfredl <bjorn.linse@gmail.com> | 2026-09-08 12:46:24 +0200 |
| commit | 97660307f5ac10d01febd7ffba63dfeb24d10351 (patch) | |
| tree | 233bdcd77cd7acf854b7ebde8ceddad6bfe9f149 /src/nvim/lua/executor.c | |
| parent | 45b645718c804b66394231f85f52413218fdafbd (diff) | |
| download | rneovim-97660307f5ac10d01febd7ffba63dfeb24d10351.tar.gz rneovim-97660307f5ac10d01febd7ffba63dfeb24d10351.tar.bz2 rneovim-97660307f5ac10d01febd7ffba63dfeb24d10351.zip | |
fix(strings): non fatal errors for [NULL] safety in vim_snprintf
context: vim_snprintf provides a "portable" replacement for a system
vsnprintf(). However we rely on system vsnprintf() in places. This
is quite arbitrary. I want to use system vsnprintf() only, and
reduce the machinery in string.c for typval printf only, which will
delet a lot of duplicated code.
The biggest hurdle here is not "portably" (we only support sane c
runtimes) but the following discrepancy: standard libc printf()
considers NULL args to %s to be undefined behavior strictly
while vim_snprintf() _defacto_ allows this by replacement to "[NULL]"
IMO, this should be seen as "graceful" error handling (nicer than crashing
on the user), not a valid means to have the string "[NULL]" intentionally
be shoved in the users face. more robust code should explicitly
check for NULL and replace it with a _appropriate_ fallback for
the situation, depending on what a NULL string actually means in the
context (unnamed buffer? anonymous namespace? global augroup?)
soo, this PR provides the most _gently_ incremental nudge towards
considering this case again as an error one could possible imagine.
If sanitizers are complied in, this minor incursion gets printed
into the sanitizers' log as a "report-and-continue" error with a
traceback. This doesn't annoy the end user or "stop the world"
in the test suite, but the CI will see the reported error and
fail the build, just like other non-fatal CI errors.
Diffstat (limited to 'src/nvim/lua/executor.c')
| -rw-r--r-- | src/nvim/lua/executor.c | 17 |
1 files changed, 5 insertions, 12 deletions
diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 5ac5e7203b..29c31a4c82 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -1131,12 +1131,6 @@ static void nlua_print_event(void **argv) static int nlua_print(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL { -#define PRINT_ERROR(msg) \ - do { \ - errmsg = msg; \ - errmsg_len = sizeof(msg) - 1; \ - goto nlua_print_error; \ - } while (0) const int nargs = lua_gettop(lstate); lua_getglobal(lstate, "tostring"); const char *errmsg = NULL; @@ -1148,22 +1142,21 @@ static int nlua_print(lua_State *const lstate) lua_pushvalue(lstate, -1); // tostring lua_pushvalue(lstate, curargidx); // arg // Do not use nlua_pcall here to avoid duplicate stack trace information - if (lua_pcall(lstate, 1, 1, 0)) { - errmsg = lua_tolstring(lstate, -1, &errmsg_len); + if (lua_pcall(lstate, 1, 1, 0) || lua_type(lstate, -1) != LUA_TSTRING) { + // NB: this might try tostring once more to print a weird error from + // a __tostring methamethod but we stop after that. + errmsg = nlua_get_error(lstate, &errmsg_len); goto nlua_print_error; } + size_t len; const char *const s = lua_tolstring(lstate, -1, &len); - if (s == NULL) { - PRINT_ERROR("<Unknown error: lua_tolstring returned NULL for tostring result>"); - } ga_concat_len(&msg_ga, s, len); if (curargidx < nargs) { ga_append(&msg_ga, ' '); } lua_pop(lstate, 1); } -#undef PRINT_ERROR ga_append(&msg_ga, NUL); lua_getfield(lstate, LUA_REGISTRYINDEX, "nvim.thread"); |