diff --git a/src/nvim/eval/fs.c b/src/nvim/eval/fs.c index d320229e2b..dfa86541e2 100644 --- a/src/nvim/eval/fs.c +++ b/src/nvim/eval/fs.c @@ -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)) { diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 838f340de1..fea7eafc9d 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -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). diff --git a/test/functional/vimscript/fnamemodify_spec.lua b/test/functional/vimscript/fnamemodify_spec.lua index f2b4b4950f..999921c218 100644 --- a/test/functional/vimscript/fnamemodify_spec.lua +++ b/test/functional/vimscript/fnamemodify_spec.lua @@ -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'))