summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2016-05-09 20:38:53 +0200
committerBram Moolenaar <Bram@vim.org>2016-05-09 20:38:53 +0200
commite0f76d00979c972329f6c371463a20da61ccad65 (patch)
treee28e61d582639de36a5885f47333ae7d63a90dc1
parentfb6ffc732e65dbc459c89247ff78134402f1a18b (diff)
downloadvim-git-7.4.1828.tar.gz
patch 7.4.1828v7.4.1828
Problem: May try to access buffer that's already freed. Solution: When freeing a buffer remove it from any channel.
-rw-r--r--src/buffer.c3
-rw-r--r--src/channel.c67
-rw-r--r--src/proto/channel.pro1
-rw-r--r--src/version.c2
4 files changed, 59 insertions, 14 deletions
diff --git a/src/buffer.c b/src/buffer.c
index 9bc24bc12..e884f55dd 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -676,6 +676,9 @@ free_buffer(buf_T *buf)
#ifdef FEAT_RUBY
ruby_buffer_free(buf);
#endif
+#ifdef FEAT_JOB_CHANNEL
+ channel_buffer_free(buf);
+#endif
#ifdef FEAT_AUTOCMD
aubuflocal_remove(buf);
if (autocmd_busy)
diff --git a/src/channel.c b/src/channel.c
index a7f4c4b8c..c191c2a0f 100644
--- a/src/channel.c
+++ b/src/channel.c
@@ -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.
+ * Returns NULL if there is something very wrong (error already reported).
*/
static buf_T *
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,
NULL, (linenr_T)0, BLN_LISTED);
+ if (buf == NULL)
+ return NULL;
buf_copy_options(buf, BCO_ENTER);
curbuf = buf;
#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)
{
+ buf_T *buf;
+
/* writing output to a buffer. Default mode is NL. */
if (!(opt->jo_set & JO_OUT_MODE))
channel->ch_part[PART_OUT].ch_mode = MODE_NL;
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
- channel->ch_part[PART_OUT].ch_buffer =
- 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);
+ {
+ buf = find_buffer(opt->jo_io_name[PART_OUT], FALSE);
+ }
+ 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
|| (opt->jo_io[PART_ERR] == JIO_OUT && (opt->jo_set & JO_OUT_IO)
&& opt->jo_io[PART_OUT] == JIO_BUFFER)))
{
+ buf_T *buf;
+
/* writing err to a buffer. Default mode is NL. */
if (!(opt->jo_set & JO_ERR_MODE))
channel->ch_part[PART_ERR].ch_mode = MODE_NL;
if (opt->jo_io[PART_ERR] == JIO_OUT)
- channel->ch_part[PART_ERR].ch_buffer =
- channel->ch_part[PART_OUT].ch_buffer;
+ buf = channel->ch_part[PART_OUT].ch_buffer;
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
- channel->ch_part[PART_ERR].ch_buffer =
- find_buffer(opt->jo_io_name[PART_ERR], TRUE);
- ch_logs(channel, "writing err to buffer '%s'",
- (char *)channel->ch_part[PART_ERR].ch_buffer->b_ffname);
+ buf = find_buffer(opt->jo_io_name[PART_ERR], TRUE);
+ if (buf != NULL)
+ {
+ 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];
@@ -1388,6 +1408,25 @@ channel_write_in(channel_T *channel)
}
/*
+ * 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.
*/
void
diff --git a/src/proto/channel.pro b/src/proto/channel.pro
index 5e0bec54b..5dc512181 100644
--- a/src/proto/channel.pro
+++ b/src/proto/channel.pro
@@ -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_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_buffer_free(buf_T *buf);
void channel_write_any_lines(void);
void channel_write_new_lines(buf_T *buf);
char_u *channel_get(channel_T *channel, int part);
diff --git a/src/version.c b/src/version.c
index 266e59148..fb3b3d48b 100644
--- a/src/version.c
+++ b/src/version.c
@@ -754,6 +754,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 1828,
+/**/
1827,
/**/
1826,