fix(coverity): RESOURCE_LEAK, USE_AFTER_FREE

/src/nvim/ex_docmd.c: 5033             in ex_restart()
    5027         // The address after --listen may be in use by the current server.
    5028         if (i > 0 && strequal(arg, "--listen")) {
    5029           const listitem_T *next_li = li->li_next;
    5030           if (next_li != NULL) {
    5031             const char *addr = tv_get_string(TV_LIST_ITEM_TV(next_li));
    5032             if (strstr(addr, ":") || strstr(addr, "/") || strstr(addr, "\\")) {
    >>>     CID 649201:         Resource leaks  (RESOURCE_LEAK)
    >>>     Overwriting "listen_arg" in "listen_arg = xstrdup(addr)" leaks the storage that "listen_arg" points to.
    5033               listen_arg = TO_SLASH_SAVE(addr);
    5034     #ifdef MSWIN
    5035               // On Windows, don't pass --listen to new server (named pipe can't be reused immediately).
    5036               // Instead pass the address via RPC; new server rebinds after startup.
    5037               li = next_li;
    5038               continue;

    *** CID 649200:         Memory - illegal accesses  (USE_AFTER_FREE)
    /src/nvim/eval/fs.c: 228             in modify_fname()
    222
    223       // ":h" - head, remove "/file_name", can be repeated
    224       // Don't remove the logical root, see `FileInfo`.
    225       while (src[*usedlen] == ':' && src[*usedlen + 1] == 'h') {
    226         valid |= VALID_HEAD;
    227         *usedlen += 2;
    >>>     CID 649200:         Memory - illegal accesses  (USE_AFTER_FREE)
    >>>     Using freed pointer "s".
    228         while (tail > s && after_pathsep(s, tail)) {
    229           MB_PTR_BACK(*fnamep, tail);
    230         }
    231         *fnamelen = tail <= s ? (size_t)(s - *fnamep) : (size_t)(tail - *fnamep);
    232         if (*fnamelen == 0) {
    233           // Result is empty.  Turn it into "." to make ":cd %:h" work.
This commit is contained in:
Justin M. Keyes
2026-07-13 05:46:46 +02:00
parent 3a7989f4f4
commit e1c1bd3722
3 changed files with 6 additions and 0 deletions

View File

@@ -233,6 +233,7 @@ repeat:
// Result is empty. Turn it into "." to make ":cd %:h" work.
xfree(*bufp);
*bufp = *fnamep = tail = xstrdup(".");
s = *fnamep; // s pointed into the freed buffer.
*fnamelen = 1;
} else {
while (tail > s && !after_pathsep(s, tail)) {

View File

@@ -5030,6 +5030,7 @@ static void ex_restart(exarg_T *eap)
if (next_li != NULL) {
const char *addr = tv_get_string(TV_LIST_ITEM_TV(next_li));
if (strstr(addr, ":") || strstr(addr, "/") || strstr(addr, "\\")) {
XFREE_CLEAR(listen_arg);
listen_arg = TO_SLASH_SAVE(addr);
#ifdef MSWIN
// On Windows, don't pass --listen to new server (named pipe can't be reused immediately).

View File

@@ -104,6 +104,10 @@ describe('fnamemodify()', function()
it('handles :h', function()
-- generic path
eq('.', fnamemodify('hello.txt', ':h'))
-- Repeated ":h" on a bare name: the first ":h" replaces the buffer with ".", the
-- next must re-anchor into it and not read the freed buffer (Coverity CID 649200).
eq('.', fnamemodify('hello.txt', ':h:h'))
eq('.', fnamemodify('hello.txt', ':h:h:h'))
eq('path/to', fnamemodify('path/to/hello.txt', ':h'))
eq('/', fnamemodify('/', ':h'))
eq('/', fnamemodify('/foo', ':h'))