# HG changeset patch # User Christian Brabandt # Date 1462105806 -7200 # Node ID 87c2e43a4a125d3e693e6e79ae55d164b3bdeb3d # Parent 93d6f07403aee50b39f10846f70b26c084c02e43 commit https://github.com/vim/vim/commit/b8d4905592fc26fcd09180d7d6bfefd899f2f6c6 Author: Bram Moolenaar Date: Sun May 1 14:22:16 2016 +0200 patch 7.4.1814 Problem: A channel may be garbage collected while it's still being used by a job. (James McCoy) Solution: Mark the channel as used if the job is still used. Do the same for channels that are still used. diff --git a/src/channel.c b/src/channel.c --- a/src/channel.c +++ b/src/channel.c @@ -3553,28 +3553,15 @@ set_ref_in_channel(int copyID) { int abort = FALSE; channel_T *channel; - int part; + typval_T tv; for (channel = first_channel; channel != NULL; channel = channel->ch_next) - { - for (part = PART_SOCK; part < PART_IN; ++part) + if (channel_still_useful(channel)) { - jsonq_T *head = &channel->ch_part[part].ch_json_head; - jsonq_T *item = head->jq_next; - - while (item != NULL) - { - list_T *l = item->jq_value->vval.v_list; - - if (l->lv_copyID != copyID) - { - l->lv_copyID = copyID; - abort = abort || set_ref_in_list(l, copyID, NULL); - } - item = item->jq_next; - } + tv.v_type = VAR_CHANNEL; + tv.vval.v_channel = channel; + abort = abort || set_ref_in_item(&tv, copyID, NULL, NULL); } - } return abort; } @@ -4092,6 +4079,26 @@ job_still_useful(job_T *job) && channel_still_useful(job->jv_channel))); } +/* + * Mark references in jobs that are still useful. + */ + int +set_ref_in_job(int copyID) +{ + int abort = FALSE; + job_T *job; + typval_T tv; + + for (job = first_job; job != NULL; job = job->jv_next) + if (job_still_useful(job)) + { + tv.v_type = VAR_JOB; + tv.vval.v_job = job; + abort = abort || set_ref_in_item(&tv, copyID, NULL, NULL); + } + return abort; +} + void job_unref(job_T *job) { diff --git a/src/eval.c b/src/eval.c --- a/src/eval.c +++ b/src/eval.c @@ -7024,6 +7024,7 @@ garbage_collect(int testing) #ifdef FEAT_JOB_CHANNEL abort = abort || set_ref_in_channel(copyID); + abort = abort || set_ref_in_job(copyID); #endif #ifdef FEAT_NETBEANS_INTG abort = abort || set_ref_in_nb_channel(copyID); diff --git a/src/proto/channel.pro b/src/proto/channel.pro --- a/src/proto/channel.pro +++ b/src/proto/channel.pro @@ -49,6 +49,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); +int set_ref_in_job(int copyID); void job_unref(job_T *job); int free_unused_jobs_contents(int copyID, int mask); void free_unused_jobs(int copyID, int mask); 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 */ /**/ + 1814, +/**/ 1813, /**/ 1812,