# HG changeset patch # User Christian Brabandt # Date 1464467406 -7200 # Node ID b9c1a397a8a662e9943c99edd4defa3e741b0035 # Parent 2afd9e149d88cad21300cb1dd866823647a735fc commit https://github.com/vim/vim/commit/655da31a18ef3f888acf10e68b438e2a851f7b14 Author: Bram Moolenaar Date: Sat May 28 22:22:34 2016 +0200 patch 7.4.1855 Problem: Valgrind reports memory leak for job that is not freed. Solution: Free all jobs on exit. Add test for failing job. diff --git a/src/channel.c b/src/channel.c --- a/src/channel.c +++ b/src/channel.c @@ -1285,6 +1285,7 @@ write_buf_line(buf_T *buf, linenr_T lnum 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 --- 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 --- 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 --- 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 --- 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,