Repository: neovim/neovim
File: src/nvim/buffer.c (C)

Code before:
/// buf_freeall() - free all things allocated for a buffer that are related to
/// the file.  Careful: get here with "curwin" NULL when exiting.
///
/// @param flags BFA_DEL           buffer is going to be deleted
///              BFA_WIPE          buffer is going to be wiped out
///              BFA_KEEP_UNDO     do not free undo information
///              BFA_IGNORE_ABORT  don't abort even when aborting() returns true
void buf_freeall(buf_T *buf, int flags)
{
  bool is_curbuf = (buf == curbuf);
  int is_curwin = (curwin != NULL && curwin->w_buffer == buf);
  win_T *the_curwin = curwin;
  tabpage_T *the_curtab = curtab;

  // Make sure the buffer isn't closed by autocommands.
  buf->b_locked++;
  buf->b_locked_split++;

  bufref_T bufref;
  set_bufref(&bufref, buf);

  // Disable buffer-updates for the current buffer.
  buf_updates_unload(buf, false);
  if (!bufref_valid(&bufref)) {
    // on_detach callback deleted the buffer.
    return;
  }
  if ((buf->b_ml.ml_mfp != NULL)
      && apply_autocmds(EVENT_BUFUNLOAD, buf->b_fname, buf->b_fname, false, buf)
      && !bufref_valid(&bufref)) {
    // Autocommands deleted the buffer.
    return;
  }
  if ((flags & BFA_DEL)
      && buf->b_p_bl
      && apply_autocmds(EVENT_BUFDELETE, buf->b_fname, buf->b_fname, false, buf)
      && !bufref_valid(&bufref)) {
    // Autocommands may delete the buffer.
    return;
  }
  if ((flags & BFA_WIPE)
      && apply_autocmds(EVENT_BUFWIPEOUT, buf->b_fname, buf->b_fname, false,
                        buf)
      && !bufref_valid(&bufref)) {
    // Autocommands may delete the buffer.
    return;
  }
  buf->b_locked--;
  buf->b_locked_split--;

  // If the buffer was in curwin and the window has changed, go back to that

Review comment (suggestion):
`on_detach` has textlock set, and like the autocmds below has `b_locked` set here too. Makes it pretty hard to delete the buffer, but it might still be possible; it's at least consistent with below to include the check.

Code after:
/// buf_freeall() - free all things allocated for a buffer that are related to
/// the file.  Careful: get here with "curwin" NULL when exiting.
///
/// @param flags BFA_DEL           buffer is going to be deleted
///              BFA_WIPE          buffer is going to be wiped out
///              BFA_KEEP_UNDO     do not free undo information
///              BFA_IGNORE_ABORT  don't abort even when aborting() returns true
void buf_freeall(buf_T *buf, int flags)
{
  bool is_curbuf = (buf == curbuf);
  int is_curwin = (curwin != NULL && curwin->w_buffer == buf);
  win_T *the_curwin = curwin;
  tabpage_T *the_curtab = curtab;

  // Make sure the buffer isn't closed by autocommands.
  buf->b_locked++;
  buf->b_locked_split++;

  bufref_T bufref;
  set_bufref(&bufref, buf);

  buf_updates_unload(buf, false);
  if (!bufref_valid(&bufref)) {
    // on_detach callback deleted the buffer.
    return;
  }
  if ((buf->b_ml.ml_mfp != NULL)
      && apply_autocmds(EVENT_BUFUNLOAD, buf->b_fname, buf->b_fname, false, buf)
      && !bufref_valid(&bufref)) {
    // Autocommands deleted the buffer.
    return;
  }
  if ((flags & BFA_DEL)
      && buf->b_p_bl
      && apply_autocmds(EVENT_BUFDELETE, buf->b_fname, buf->b_fname, false, buf)
      && !bufref_valid(&bufref)) {
    // Autocommands may delete the buffer.
    return;
  }
  if ((flags & BFA_WIPE)
      && apply_autocmds(EVENT_BUFWIPEOUT, buf->b_fname, buf->b_fname, false,
                        buf)
      && !bufref_valid(&bufref)) {
    // Autocommands may delete the buffer.
    return;
  }
  buf->b_locked--;
  buf->b_locked_split--;

  // If the buffer was in curwin and the window has changed, go back to that
  // window, if it still exists.  This avoids that ":edit x" triggering a