]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 7.4.1828 v7.4.1828
authorBram Moolenaar <Bram@vim.org>
Mon, 9 May 2016 18:38:53 +0000 (20:38 +0200)
committerBram Moolenaar <Bram@vim.org>
Mon, 9 May 2016 18:38:53 +0000 (20:38 +0200)
Problem:    May try to access buffer that's already freed.
Solution:   When freeing a buffer remove it from any channel.

src/buffer.c
src/channel.c
src/proto/channel.pro
src/version.c

index 9bc24bc12684c0ed352929a576b72580142a652c..e884f55dd76ea8c666e3df1261f945ff7d9744ec 100644 (file)
@@ -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)
index a7f4c4b8cb0fefc6b3dedc3562480f75b5081061..c191c2a0ffbeef9385cb3d2cac776a3c2c4c724b 100644 (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.
+ * 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];
@@ -1387,6 +1407,25 @@ channel_write_in(channel_T *channel)
                                          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.
  */
index 5e0bec54b539a939ff3e33f0546c188a2825fa46..5dc512181f1b2e197001f96864457d5849ba4d9b 100644 (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_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);
index 266e591488d234c8890d7fc0221eed9657a83b2a..fb3b3d48b9fd9526dec89cb5ff10f89b9d44d812 100644 (file)
@@ -753,6 +753,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1828,
 /**/
     1827,
 /**/