Loading ...
Sorry, an error occurred while loading the content.
 

crash when deleting other buffers in BufUnload autocommand

Expand Messages
  • Andrew Pimlott
    I have a plugin that wants to manage a group of related buffers, and when one is unloaded they all should be. And if that is all the buffers there are, vim
    Message 1 of 4 , Aug 11, 2012
      I have a plugin that wants to manage a group of related buffers, and
      when one is unloaded they all should be. And if that is all the buffers
      there are, vim should exit. So I implemented a BufUnload autocommand
      that would unload all the related buffers.

      I realize that the help for BufUnload says not to change to another
      buffer. Still, I found a method that worked in many versions of vim
      over time. But sometime between 7.3.363 and 7.3.547, it started
      crashing. You can reproduce with this test.vim:

      set nohidden
      au! BufUnload * call Unload()
      function Unload()
      " unload the related buffers; switching to a new buffer
      " first made this work in older versions of vim
      new
      bunload 1
      bunload 2
      q
      endfunction

      Then run "vi -o f1 f2", ":source test.vim", and ":q". In 7.3.547, this
      seg faults with this backtrace:

      #0 ml_get_buf (buf=0x0, lnum=1, will_change=0) at memline.c:2429
      #1 0x00000000004cc060 in plines_win_nofold (wp=0x8fcab0, lnum=<optimized out>)
      at misc1.c:1911
      #2 0x00000000004cc175 in plines_win_nofill (winheight=1, lnum=1, wp=0x8fcab0)
      at misc1.c:1892
      #3 plines_win_nofill (wp=0x8fcab0, lnum=1, winheight=1) at misc1.c:1869
      #4 0x00000000004dfa4a in curs_rows (wp=0x8fcab0, do_botline=<optimized out>)
      at move.c:747
      #5 curs_columns (may_scroll=1) at move.c:953
      #6 0x000000000058e385 in main_loop (cmdwin=0, noexmode=0) at main.c:1192
      #7 0x000000000042d0ca in main (argc=<optimized out>, argv=<optimized out>)
      at main.c:1001

      memline.c:2429 is

      if (lnum > buf->b_ml.ml_line_count) /* invalid line number */

      buf is NUL.

      In earlier vims, it would exit as desired.

      Is there a safe way to do what I want?

      Andrew

      --
      You received this message from the "vim_dev" maillist.
      Do not top-post! Type your reply below the text you are replying to.
      For more information, visit http://www.vim.org/maillist.php
    • Tony Mechelynck
      ... Well, your :new command does change to a new buffer, something which is explicitly documented as forbidden because it will cause problems . So you were
      Message 2 of 4 , Aug 11, 2012
        On 11/08/12 16:18, Andrew Pimlott wrote:
        > I have a plugin that wants to manage a group of related buffers, and
        > when one is unloaded they all should be. And if that is all the buffers
        > there are, vim should exit. So I implemented a BufUnload autocommand
        > that would unload all the related buffers.
        >
        > I realize that the help for BufUnload says not to change to another
        > buffer. Still, I found a method that worked in many versions of vim
        > over time. But sometime between 7.3.363 and 7.3.547, it started
        > crashing. You can reproduce with this test.vim:
        >
        > set nohidden
        > au! BufUnload * call Unload()
        > function Unload()
        > " unload the related buffers; switching to a new buffer
        > " first made this work in older versions of vim
        > new
        > bunload 1
        > bunload 2
        > q
        > endfunction
        >
        > Then run "vi -o f1 f2", ":source test.vim", and ":q". In 7.3.547, this
        > seg faults with this backtrace:
        >
        > #0 ml_get_buf (buf=0x0, lnum=1, will_change=0) at memline.c:2429
        > #1 0x00000000004cc060 in plines_win_nofold (wp=0x8fcab0, lnum=<optimized out>)
        > at misc1.c:1911
        > #2 0x00000000004cc175 in plines_win_nofill (winheight=1, lnum=1, wp=0x8fcab0)
        > at misc1.c:1892
        > #3 plines_win_nofill (wp=0x8fcab0, lnum=1, winheight=1) at misc1.c:1869
        > #4 0x00000000004dfa4a in curs_rows (wp=0x8fcab0, do_botline=<optimized out>)
        > at move.c:747
        > #5 curs_columns (may_scroll=1) at move.c:953
        > #6 0x000000000058e385 in main_loop (cmdwin=0, noexmode=0) at main.c:1192
        > #7 0x000000000042d0ca in main (argc=<optimized out>, argv=<optimized out>)
        > at main.c:1001
        >
        > memline.c:2429 is
        >
        > if (lnum > buf->b_ml.ml_line_count) /* invalid line number */
        >
        > buf is NUL.
        >
        > In earlier vims, it would exit as desired.
        >
        > Is there a safe way to do what I want?
        >
        > Andrew
        >

        Well, your ":new" command does change to a new buffer, something which
        is explicitly documented as forbidden because "it will cause problems".

        So you were taking advantage of a bug (the bug, which still exists,
        being that issuing :new in a BufUnload autocommand doesn't give an
        error). At some point the unsupported behaviour of the command you were
        abusing changed. Well, you will just have to find something else.

        Maybe (untested) set a variable to 0 in your vimrc, set it to the buffer
        number in the BufUnload autocommand, test it in, let's say, an
        autocommand for CursorHold, CursorHoldI, CursorMoved and CursorMovedI,
        and if found in the correct range, unload all _other_ buffers in your
        buffer set.


        Best regards,
        Tony.
        --
        Binary, adj.:
        Possessing the ability to have friends of both sexes.

        --
        You received this message from the "vim_dev" maillist.
        Do not top-post! Type your reply below the text you are replying to.
        For more information, visit http://www.vim.org/maillist.php
      • Andrew Pimlott
        ... Yes, that s what I m looking for. :-) I don t want to depend on undefined behavior. On the other hand, maybe it is not that hard to change vim to allow
        Message 3 of 4 , Aug 11, 2012
          Excerpts from Tony Mechelynck's message of Sat Aug 11 08:32:04 -0700 2012:
          > Well, your ":new" command does change to a new buffer, something which
          > is explicitly documented as forbidden because "it will cause problems".
          >
          > So you were taking advantage of a bug (the bug, which still exists,
          > being that issuing :new in a BufUnload autocommand doesn't give an
          > error). At some point the unsupported behaviour of the command you were
          > abusing changed. Well, you will just have to find something else.

          Yes, that's what I'm looking for. :-) I don't want to depend on
          undefined behavior. On the other hand, maybe it is not that hard to
          change vim to allow this....

          By the way, even this crashes when I run my example:

          set nohidden
          au! BufUnload * call Unload()
          function Unload()
          bunload 2
          endfunction

          Note it neither changes buffers nor changes the current buffer, so it is
          not doing anything explicitly forbidden. But this crashed in older
          versions of vim too, which is why I came up with the "new ... q"
          approach. I would be just as happy if the above worked!

          > Maybe (untested) set a variable to 0 in your vimrc, set it to the buffer
          > number in the BufUnload autocommand, test it in, let's say, an
          > autocommand for CursorHold, CursorHoldI, CursorMoved and CursorMovedI,
          > and if found in the correct range, unload all _other_ buffers in your
          > buffer set.

          Interesting idea.... I think that before going that route, I would just
          map all of the quitting or buffer closing commands.

          Andrew

          --
          You received this message from the "vim_dev" maillist.
          Do not top-post! Type your reply below the text you are replying to.
          For more information, visit http://www.vim.org/maillist.php
        • Tony Mechelynck
          ... It changes buffers if you happen to execute it while buffer 2 is current. ... Best regards, Tony. -- A pretty young maiden from France Decided she d just
          Message 4 of 4 , Aug 11, 2012
            On 11/08/12 18:15, Andrew Pimlott wrote:
            > Excerpts from Tony Mechelynck's message of Sat Aug 11 08:32:04 -0700 2012:
            >> Well, your ":new" command does change to a new buffer, something which
            >> is explicitly documented as forbidden because "it will cause problems".
            >>
            >> So you were taking advantage of a bug (the bug, which still exists,
            >> being that issuing :new in a BufUnload autocommand doesn't give an
            >> error). At some point the unsupported behaviour of the command you were
            >> abusing changed. Well, you will just have to find something else.
            >
            > Yes, that's what I'm looking for. :-) I don't want to depend on
            > undefined behavior. On the other hand, maybe it is not that hard to
            > change vim to allow this....
            >
            > By the way, even this crashes when I run my example:
            >
            > set nohidden
            > au! BufUnload * call Unload()
            > function Unload()
            > bunload 2
            > endfunction
            >
            > Note it neither changes buffers nor changes the current buffer, so it is
            > not doing anything explicitly forbidden. But this crashed in older
            > versions of vim too, which is why I came up with the "new ... q"
            > approach. I would be just as happy if the above worked!

            It changes buffers if you happen to execute it while buffer 2 is current.

            >
            >> Maybe (untested) set a variable to 0 in your vimrc, set it to the buffer
            >> number in the BufUnload autocommand, test it in, let's say, an
            >> autocommand for CursorHold, CursorHoldI, CursorMoved and CursorMovedI,
            >> and if found in the correct range, unload all _other_ buffers in your
            >> buffer set.
            >
            > Interesting idea.... I think that before going that route, I would just
            > map all of the quitting or buffer closing commands.
            >
            > Andrew
            >

            Best regards,
            Tony.
            --
            A pretty young maiden from France
            Decided she'd "just take a chance."
            She let herself go
            For an hour or so
            And now all her sisters are aunts.

            --
            You received this message from the "vim_dev" maillist.
            Do not top-post! Type your reply below the text you are replying to.
            For more information, visit http://www.vim.org/maillist.php
          Your message has been successfully submitted and would be delivered to recipients shortly.