1
0
forked from aniani/vim

patch 7.4.1828

Problem:    May try to access buffer that's already freed.
Solution:   When freeing a buffer remove it from any channel.
This commit is contained in:
Bram Moolenaar
2016-05-09 20:38:53 +02:00
parent fb6ffc732e
commit e0f76d0097
4 changed files with 59 additions and 14 deletions

View File

@@ -676,6 +676,9 @@ free_buffer(buf_T *buf)
#ifdef FEAT_RUBY #ifdef FEAT_RUBY
ruby_buffer_free(buf); ruby_buffer_free(buf);
#endif #endif
#ifdef FEAT_JOB_CHANNEL
channel_buffer_free(buf);
#endif
#ifdef FEAT_AUTOCMD #ifdef FEAT_AUTOCMD
aubuflocal_remove(buf); aubuflocal_remove(buf);
if (autocmd_busy) if (autocmd_busy)

View File

@@ -1068,6 +1068,7 @@ channel_set_job(channel_T *channel, job_T *job, jobopt_T *options)
/* /*
* Find a buffer matching "name" or create a new one. * Find a buffer matching "name" or create a new one.
* Returns NULL if there is something very wrong (error already reported).
*/ */
static buf_T * static buf_T *
find_buffer(char_u *name, int err) find_buffer(char_u *name, int err)
@@ -1081,6 +1082,8 @@ find_buffer(char_u *name, int err)
{ {
buf = buflist_new(name == NULL || *name == NUL ? NULL : name, buf = buflist_new(name == NULL || *name == NUL ? NULL : name,
NULL, (linenr_T)0, BLN_LISTED); NULL, (linenr_T)0, BLN_LISTED);
if (buf == NULL)
return NULL;
buf_copy_options(buf, BCO_ENTER); buf_copy_options(buf, BCO_ENTER);
curbuf = buf; curbuf = buf;
#ifdef FEAT_QUICKFIX #ifdef FEAT_QUICKFIX
@@ -1187,37 +1190,54 @@ channel_set_options(channel_T *channel, jobopt_T *opt)
if ((opt->jo_set & JO_OUT_IO) && opt->jo_io[PART_OUT] == JIO_BUFFER) if ((opt->jo_set & JO_OUT_IO) && opt->jo_io[PART_OUT] == JIO_BUFFER)
{ {
buf_T *buf;
/* writing output to a buffer. Default mode is NL. */ /* writing output to a buffer. Default mode is NL. */
if (!(opt->jo_set & JO_OUT_MODE)) if (!(opt->jo_set & JO_OUT_MODE))
channel->ch_part[PART_OUT].ch_mode = MODE_NL; channel->ch_part[PART_OUT].ch_mode = MODE_NL;
if (opt->jo_set & JO_OUT_BUF) if (opt->jo_set & JO_OUT_BUF)
channel->ch_part[PART_OUT].ch_buffer = {
buflist_findnr(opt->jo_io_buf[PART_OUT]); buf = buflist_findnr(opt->jo_io_buf[PART_OUT]);
if (buf == NULL)
EMSGN(_(e_nobufnr), (long)opt->jo_io_buf[PART_OUT]);
}
else else
channel->ch_part[PART_OUT].ch_buffer = {
find_buffer(opt->jo_io_name[PART_OUT], FALSE); buf = find_buffer(opt->jo_io_name[PART_OUT], FALSE);
ch_logs(channel, "writing out to buffer '%s'", }
(char *)channel->ch_part[PART_OUT].ch_buffer->b_ffname); if (buf != NULL)
{
ch_logs(channel, "writing out to buffer '%s'",
(char *)buf->b_ffname);
channel->ch_part[PART_OUT].ch_buffer = buf;
}
} }
if ((opt->jo_set & JO_ERR_IO) && (opt->jo_io[PART_ERR] == JIO_BUFFER if ((opt->jo_set & JO_ERR_IO) && (opt->jo_io[PART_ERR] == JIO_BUFFER
|| (opt->jo_io[PART_ERR] == JIO_OUT && (opt->jo_set & JO_OUT_IO) || (opt->jo_io[PART_ERR] == JIO_OUT && (opt->jo_set & JO_OUT_IO)
&& opt->jo_io[PART_OUT] == JIO_BUFFER))) && opt->jo_io[PART_OUT] == JIO_BUFFER)))
{ {
buf_T *buf;
/* writing err to a buffer. Default mode is NL. */ /* writing err to a buffer. Default mode is NL. */
if (!(opt->jo_set & JO_ERR_MODE)) if (!(opt->jo_set & JO_ERR_MODE))
channel->ch_part[PART_ERR].ch_mode = MODE_NL; channel->ch_part[PART_ERR].ch_mode = MODE_NL;
if (opt->jo_io[PART_ERR] == JIO_OUT) if (opt->jo_io[PART_ERR] == JIO_OUT)
channel->ch_part[PART_ERR].ch_buffer = buf = channel->ch_part[PART_OUT].ch_buffer;
channel->ch_part[PART_OUT].ch_buffer;
else if (opt->jo_set & JO_ERR_BUF) else if (opt->jo_set & JO_ERR_BUF)
channel->ch_part[PART_ERR].ch_buffer = {
buflist_findnr(opt->jo_io_buf[PART_ERR]); buf = buflist_findnr(opt->jo_io_buf[PART_ERR]);
if (buf == NULL)
EMSGN(_(e_nobufnr), (long)opt->jo_io_buf[PART_ERR]);
}
else else
channel->ch_part[PART_ERR].ch_buffer = buf = find_buffer(opt->jo_io_name[PART_ERR], TRUE);
find_buffer(opt->jo_io_name[PART_ERR], TRUE); if (buf != NULL)
ch_logs(channel, "writing err to buffer '%s'", {
(char *)channel->ch_part[PART_ERR].ch_buffer->b_ffname); ch_logs(channel, "writing err to buffer '%s'",
(char *)buf->b_ffname);
channel->ch_part[PART_ERR].ch_buffer = buf;
}
} }
channel->ch_part[PART_OUT].ch_io = opt->jo_io[PART_OUT]; channel->ch_part[PART_OUT].ch_io = opt->jo_io[PART_OUT];
@@ -1387,6 +1407,25 @@ channel_write_in(channel_T *channel)
buf->b_ml.ml_line_count - lnum + 1); buf->b_ml.ml_line_count - lnum + 1);
} }
/*
* Handle buffer "buf" beeing freed, remove it from any channels.
*/
void
channel_buffer_free(buf_T *buf)
{
channel_T *channel;
int part;
for (channel = first_channel; channel != NULL; channel = channel->ch_next)
for (part = PART_SOCK; part <= PART_IN; ++part)
{
chanpart_T *ch_part = &channel->ch_part[part];
if (ch_part->ch_buffer == buf)
ch_part->ch_buffer = NULL;
}
}
/* /*
* Write any lines waiting to be written to a channel. * Write any lines waiting to be written to a channel.
*/ */

View File

@@ -14,6 +14,7 @@ void channel_set_pipes(channel_T *channel, sock_T in, sock_T out, sock_T err);
void channel_set_job(channel_T *channel, job_T *job, jobopt_T *options); void channel_set_job(channel_T *channel, job_T *job, jobopt_T *options);
void channel_set_options(channel_T *channel, jobopt_T *opt); void channel_set_options(channel_T *channel, jobopt_T *opt);
void channel_set_req_callback(channel_T *channel, int part, char_u *callback, partial_T *partial, int id); void channel_set_req_callback(channel_T *channel, int part, char_u *callback, partial_T *partial, int id);
void channel_buffer_free(buf_T *buf);
void channel_write_any_lines(void); void channel_write_any_lines(void);
void channel_write_new_lines(buf_T *buf); void channel_write_new_lines(buf_T *buf);
char_u *channel_get(channel_T *channel, int part); char_u *channel_get(channel_T *channel, int part);

View File

@@ -753,6 +753,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
1828,
/**/ /**/
1827, 1827,
/**/ /**/