summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2016-05-28 22:22:34 +0200
committerBram Moolenaar <Bram@vim.org>2016-05-28 22:22:34 +0200
commit655da31a18ef3f888acf10e68b438e2a851f7b14 (patch)
tree83d8a9b03a2d926d7b94092e975a66f679fd1b70
parentd80629cef03cd40b0bf06c402dfe0b720b3bf608 (diff)
patch 7.4.1855v7.4.1855
Problem: Valgrind reports memory leak for job that is not freed. Solution: Free all jobs on exit. Add test for failing job.
-rw-r--r--src/channel.c12
-rw-r--r--src/misc2.c7
-rw-r--r--src/proto/channel.pro1
-rw-r--r--src/testdir/test_partial.vim14
-rw-r--r--src/version.c2
5 files changed, 32 insertions, 4 deletions
diff --git a/src/channel.c b/src/channel.c
index 94681ee898..2cc46fecb7 100644
--- a/src/channel.c
+++ b/src/channel.c
@@ -1285,6 +1285,7 @@ write_buf_line(buf_T *buf, linenr_T lnum, channel_T *channel)
int len = (int)STRLEN(line);
char_u *p;
+ /* Need to make a copy to be able to append a NL. */
if ((p = alloc(len + 2)) == NULL)
return;
STRCPY(p, line);
@@ -2888,7 +2889,7 @@ channel_close_now(channel_T *channel)
/*
* Read from channel "channel" for as long as there is something to read.
* "part" is PART_SOCK, PART_OUT or PART_ERR.
- * The data is put in the read queue.
+ * The data is put in the read queue. No callbacks are invoked here.
*/
static void
channel_read(channel_T *channel, int part, char *func)
@@ -4184,6 +4185,15 @@ job_free(job_T *job)
}
}
+#if defined(EXITFREE) || defined(PROTO)
+ void
+job_free_all(void)
+{
+ while (first_job != NULL)
+ job_free(first_job);
+}
+#endif
+
/*
* Return TRUE if the job should not be freed yet. Do not free the job when
* it has not ended yet and there is a "stoponexit" flag, an exit callback
diff --git a/src/misc2.c b/src/misc2.c
index a0cce07f66..b4e94795f1 100644
--- a/src/misc2.c
+++ b/src/misc2.c
@@ -1127,9 +1127,6 @@ free_all_mem(void)
# ifdef FEAT_DIFF
diff_clear(curtab);
# endif
-# ifdef FEAT_JOB_CHANNEL
- channel_free_all();
-# endif
clear_sb_text(); /* free any scrollback text */
/* Free some global vars. */
@@ -1221,6 +1218,10 @@ free_all_mem(void)
# ifdef FEAT_EVAL
eval_clear();
# endif
+# ifdef FEAT_JOB_CHANNEL
+ channel_free_all();
+ job_free_all();
+# endif
free_termoptions();
diff --git a/src/proto/channel.pro b/src/proto/channel.pro
index 5dc512181f..60b68f0133 100644
--- a/src/proto/channel.pro
+++ b/src/proto/channel.pro
@@ -50,6 +50,7 @@ void clear_job_options(jobopt_T *opt);
void free_job_options(jobopt_T *opt);
int get_job_options(typval_T *tv, jobopt_T *opt, int supported);
channel_T *get_channel_arg(typval_T *tv, int check_open, int reading, int part);
+void job_free_all(void);
int set_ref_in_job(int copyID);
void job_unref(job_T *job);
int free_unused_jobs_contents(int copyID, int mask);
diff --git a/src/testdir/test_partial.vim b/src/testdir/test_partial.vim
index af6ca6db25..f33aab3a1a 100644
--- a/src/testdir/test_partial.vim
+++ b/src/testdir/test_partial.vim
@@ -250,6 +250,20 @@ func Test_cycle_partial_job()
endif
endfunc
+func Test_job_start_fails()
+ if has('job')
+ let job = job_start('axdfxsdf')
+ for i in range(100)
+ if job_status(job) == 'dead'
+ break
+ endif
+ sleep 10m
+ endfor
+ call assert_equal('dead', job_status(job))
+ unlet job
+ endif
+endfunc
+
func Test_ref_job_partial_dict()
if has('job')
let g:ref_job = job_start('echo')
diff --git a/src/version.c b/src/version.c
index 2ec25c0b5e..e68c4ec05f 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 */
/**/
+ 1855,
+/**/
1854,
/**/
1853,