neovim

Neovim text editor
git clone https://git.dasho.dev/neovim.git
Log | Files | Refs | README

commit 09f9d72c249588252f44d2fa5eddd50436acd6ba
parent cf5506f0fde13e61398b6a5121a5c673b0646765
Author: glepnir <glephunter@gmail.com>
Date:   Sun,  6 Jul 2025 20:27:20 +0800

fix(runtime): coverity STRING_NULL #569464 (#34795)

Problem:
Coverity reports string null termination issue:

    *** CID 569464:  Memory - string handling  (STRING_NULL)
    /src/nvim/runtime.c: 1374 in ExpandRTDir_int()
    1372         if (flags & DIP_START) {
    1373           memcpy(tail - 15, "pack/*/start/*/", 15);  // NOLINT
    >>>     CID 569464:  Memory - string handling  (STRING_NULL)
    >>>     Passing unterminated string "tail - 15" to "globpath", which expects a null-terminated string.
    1374           globpath(p_pp, tail - 15, gap, glob_flags, expand_dirs);

    Similar issues occur at lines 1376, 1381, and 1383 where memcpy()
    constructs strings passed to globpath() without null termination.

Solution:
Replace dangerous pointer arithmetic and memcpy() with direct snprintf()
construction of complete search paths. This eliminates the need for
buffer reuse through pointer offsets and ensures all strings passed to
globpath() are properly null-terminated.

vim-patch:9.1.1515: Coverity complains about potential unterminated strings
Diffstat:
Msrc/nvim/runtime.c | 47++++++++++++++++++++++++++---------------------
1 file changed, 26 insertions(+), 21 deletions(-)

diff --git a/src/nvim/runtime.c b/src/nvim/runtime.c @@ -1351,41 +1351,46 @@ static void ExpandRTDir_int(char *pat, size_t pat_len, int flags, bool keep_ext, { // TODO(bfredl): this is bullshit, expandpath should not reinvent path logic. for (int i = 0; dirnames[i] != NULL; i++) { - const size_t buf_len = strlen(dirnames[i]) + pat_len + 31; - char *const buf = xmalloc(buf_len); - char *const tail = buf + 15; - const size_t tail_buflen = buf_len - 15; + const size_t buf_len = strlen(dirnames[i]) + pat_len + 64; + char *buf = xmalloc(buf_len); int glob_flags = 0; bool expand_dirs = false; - - if (*dirnames[i] == NUL) { // empty dir used for :runtime - snprintf(tail, tail_buflen, "%s*.{vim,lua}", pat); - } else { - snprintf(tail, tail_buflen, "%s/%s*.{vim,lua}", dirnames[i], pat); - } + // Build base pattern + snprintf(buf, buf_len, "%s%s%s%s", *dirnames[i] ? dirnames[i] : "", *dirnames[i] ? "/" : "", + pat, "*.{vim,lua}"); expand: if ((flags & DIP_NORTP) == 0) { - globpath(p_rtp, tail, gap, glob_flags, expand_dirs); + globpath(p_rtp, buf, gap, glob_flags, expand_dirs); } if (flags & DIP_START) { - memcpy(tail - 15, "pack/*/start/*/", 15); // NOLINT - globpath(p_pp, tail - 15, gap, glob_flags, expand_dirs); - memcpy(tail - 8, "start/*/", 8); // NOLINT - globpath(p_pp, tail - 8, gap, glob_flags, expand_dirs); + // pack/*/start/*/ patterns + snprintf(buf, buf_len, "pack/*/start/*/%s%s%s%s", *dirnames[i] ? dirnames[i] : "", // NOLINT + *dirnames[i] ? "/" : "", pat, expand_dirs ? "*" : "*.{vim,lua}"); + globpath(p_pp, buf, gap, glob_flags, expand_dirs); + + // start/*/ patterns + snprintf(buf, buf_len, "start/*/%s%s%s%s", *dirnames[i] ? dirnames[i] : "", // NOLINT + *dirnames[i] ? "/" : "", pat, expand_dirs ? "*" : "*.{vim,lua}"); + globpath(p_pp, buf, gap, glob_flags, expand_dirs); } if (flags & DIP_OPT) { - memcpy(tail - 13, "pack/*/opt/*/", 13); // NOLINT - globpath(p_pp, tail - 13, gap, glob_flags, expand_dirs); - memcpy(tail - 6, "opt/*/", 6); // NOLINT - globpath(p_pp, tail - 6, gap, glob_flags, expand_dirs); + // pack/*/opt/*/ patterns + snprintf(buf, buf_len, "pack/*/opt/*/%s%s%s%s", *dirnames[i] ? dirnames[i] : "", // NOLINT + *dirnames[i] ? "/" : "", pat, expand_dirs ? "*" : "*.{vim,lua}"); + globpath(p_pp, buf, gap, glob_flags, expand_dirs); + + // opt/*/ patterns + snprintf(buf, buf_len, "opt/*/%s%s%s%s", *dirnames[i] ? dirnames[i] : "", // NOLINT + *dirnames[i] ? "/" : "", pat, expand_dirs ? "*" : "*.{vim,lua}"); + globpath(p_pp, buf, gap, glob_flags, expand_dirs); } + // Second round for directories if (*dirnames[i] == NUL && !expand_dirs) { - // expand dir names in another round - snprintf(tail, tail_buflen, "%s*", pat); + snprintf(buf, buf_len, "%s*", pat); glob_flags = WILD_ADD_SLASH; expand_dirs = true; goto expand;