Skip to content

quickfix: might use incorrect buffer through qf_last_bufname after bwipeout #1676

@blueyed

Description

@blueyed

I've found an issue where Vim might use a re-cycled buffer for a quickfix entry, that should not be used.

I could not create a more simple test case that worked reliably, but it is caused by using bwipe and new, where the buffer before the wiping gets the same %d representation (through fprintf(stderr, "buf: %d\n")).

The following is a Vader test, but should work in general - except for that it might not trigger it.
I have noticed that even adding a new line between bwipe and new might change it..

Also commenting the free_buffer in close_buffer, or rather the vim_free(buf) at the end works around it.
It seems like without it the new buffer will (more likely) get the same address as the previous one, where qf_last_bufref.br_buf points at then still?!

Execute (qf_last_bufname):
  new
  file myfile
"   edit myfile
  let &errorformat = '%f:%m'
  cgetexpr 'myfile:msg1'
  cgetexpr 'myfile:msg1'
  redir => ls
  ls!
  redir END
  Log ls
  echom string(getqflist())
  call assert_equal(getqflist()[0].bufnr, bufnr('myfile'))
  call assert_equal(bufnr('%'), bufnr('myfile'))
  AssertEqual getqflist()[0].bufnr, bufnr('myfile')
  AssertEqual bufnr('%'), bufnr('myfile')

  bwipe
  new
  cgetexpr 'myfile:msg2'
  AssertNotEqual -1, bufnr('myfile')
  call assert_notequal(-1, bufnr('myfile'))
  call assert_equal(getqflist()[0].bufnr, bufnr('myfile'))
  call assert_notequal(bufnr('%'), bufnr('myfile'))

A fix, but it might also have to compare b_ffname, and in the end qf_last_bufname/qf_last_bufref should be handled instead when a buffer is wiped?!

diff --git c/src/quickfix.c i/src/quickfix.c
index 7b07f9358..91f5259fd 100644
--- c/src/quickfix.c
+++ i/src/quickfix.c
@@ -1713,7 +1713,9 @@ qf_get_fnum(qf_info_T *qi, char_u *directory, char_u *fname)
        bufname = fname;
 
     if (qf_last_bufname != NULL && STRCMP(bufname, qf_last_bufname) == 0
-           && bufref_valid(&qf_last_bufref))
+           && bufref_valid(&qf_last_bufref)
+           && qf_last_bufref.br_buf->b_sfname
+           && STRCMP(qf_last_bufref.br_buf->b_sfname, bufname) == 0)
     {
        buf = qf_last_bufref.br_buf;
        vim_free(ptr);

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions