diff src/eval.c @ 8310:aec8f8ce8e4c v7.4.1447

commit https://github.com/vim/vim/commit/d6051b5eb83687f60bb4a2f3d5cd23fe8b290eb4 Author: Bram Moolenaar <Bram@vim.org> Date: Sun Feb 28 15:49:03 2016 +0100 patch 7.4.1447 Problem: Memory leak when using ch_read(). (Dominique Pelle) No log message when stopping a job and a few other situations. Too many "Nothing to read" messages. Channels are not freed. Solution: Free the listtv. Add more log messages. Remove "Nothing to read" message. Remove the channel from the job when its refcount becomes zero.
author Christian Brabandt <cb@256bit.org>
date Sun, 28 Feb 2016 16:00:05 +0100
parents 18fd94bd4eb8
children 4e057409f1d7
line wrap: on
line diff
--- a/src/eval.c
+++ b/src/eval.c
@@ -7741,7 +7741,7 @@ failret:
 /*
  * Decrement the reference count on "channel" and maybe free it when it goes
  * down to zero.  Don't free it if there is a pending action.
- * Returns TRUE when the channel was freed.
+ * Returns TRUE when the channel is no longer referenced.
  */
     int
 channel_unref(channel_T *channel)
@@ -7762,6 +7762,7 @@ static job_T *first_job = NULL;
 job_free(job_T *job)
 {
 # ifdef FEAT_CHANNEL
+    ch_log(job->jv_channel, "Freeing job");
     if (job->jv_channel != NULL)
     {
 	/* The link from the channel to the job doesn't count as a reference,
@@ -7796,7 +7797,17 @@ job_unref(job_T *job)
 	 * "stoponexit" flag or an exit callback. */
 	if (job->jv_status != JOB_STARTED
 		|| (job->jv_stoponexit == NULL && job->jv_exit_cb == NULL))
+	{
 	    job_free(job);
+	}
+	else if (job->jv_channel != NULL)
+	{
+	    /* Do remove the link to the channel, otherwise it hangs
+	     * around until Vim exits. See job_free() for refcount. */
+	    job->jv_channel->ch_job = NULL;
+	    channel_unref(job->jv_channel);
+	    job->jv_channel = NULL;
+	}
     }
 }
 
@@ -10467,7 +10478,10 @@ common_channel_read(typval_T *argvars, t
 		id = opt.jo_id;
 	    channel_read_json_block(channel, part, timeout, id, &listtv);
 	    if (listtv != NULL)
+	    {
 		*rettv = *listtv;
+		vim_free(listtv);
+	    }
 	    else
 	    {
 		rettv->v_type = VAR_SPECIAL;
@@ -15292,6 +15306,9 @@ f_job_stop(typval_T *argvars UNUSED, typ
 		return;
 	    }
 	}
+# ifdef FEAT_CHANNEL
+	ch_logs(job->jv_channel, "Stopping job with '%s'", (char *)arg);
+# endif
 	if (mch_stop_job(job, arg) == FAIL)
 	    rettv->vval.v_number = 0;
 	else