To: vim_dev@googlegroups.com Subject: Patch 7.4.2026 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 7.4.2026 Problem: Reference counting for callbacks isn't right. Solution: Add free_callback(). (Ken Takata) Fix reference count. Files: src/channel.c, src/eval.c, src/ex_cmds2.c, src/proto/eval.pro *** ../vim-7.4.2025/src/channel.c 2016-07-10 22:11:11.858751521 +0200 --- src/channel.c 2016-07-11 22:36:04.665368667 +0200 *************** *** 1113,1118 **** --- 1113,1135 ---- return buf; } + static void + set_callback( + char_u **cbp, + partial_T **pp, + char_u *callback, + partial_T *partial) + { + free_callback(*cbp, *pp); + if (callback != NULL && *callback != NUL) + *cbp = vim_strsave(callback); + else + *cbp = NULL; + *pp = partial; + if (*pp != NULL) + ++(*pp)->pt_refcount; + } + /* * Set various properties from an "opt" argument. */ *************** *** 1120,1127 **** channel_set_options(channel_T *channel, jobopt_T *opt) { int part; - char_u **cbp; - partial_T **pp; if (opt->jo_set & JO_MODE) for (part = PART_SOCK; part <= PART_IN; ++part) --- 1137,1142 ---- *************** *** 1144,1204 **** channel->ch_part[PART_IN].ch_block_write = 1; if (opt->jo_set & JO_CALLBACK) ! { ! cbp = &channel->ch_callback; ! pp = &channel->ch_partial; ! vim_free(*cbp); ! partial_unref(*pp); ! if (opt->jo_callback != NULL && *opt->jo_callback != NUL) ! *cbp = vim_strsave(opt->jo_callback); ! else ! *cbp = NULL; ! *pp = opt->jo_partial; ! if (*pp != NULL) ! ++(*pp)->pt_refcount; ! } if (opt->jo_set & JO_OUT_CALLBACK) ! { ! cbp = &channel->ch_part[PART_OUT].ch_callback; ! pp = &channel->ch_part[PART_OUT].ch_partial; ! vim_free(*cbp); ! partial_unref(*pp); ! if (opt->jo_out_cb != NULL && *opt->jo_out_cb != NUL) ! *cbp = vim_strsave(opt->jo_out_cb); ! else ! *cbp = NULL; ! *pp = opt->jo_out_partial; ! if (*pp != NULL) ! ++(*pp)->pt_refcount; ! } if (opt->jo_set & JO_ERR_CALLBACK) ! { ! cbp = &channel->ch_part[PART_ERR].ch_callback; ! pp = &channel->ch_part[PART_ERR].ch_partial; ! vim_free(*cbp); ! partial_unref(*pp); ! if (opt->jo_err_cb != NULL && *opt->jo_err_cb != NUL) ! *cbp = vim_strsave(opt->jo_err_cb); ! else ! *cbp = NULL; ! *pp = opt->jo_err_partial; ! if (*pp != NULL) ! ++(*pp)->pt_refcount; ! } if (opt->jo_set & JO_CLOSE_CALLBACK) ! { ! cbp = &channel->ch_close_cb; ! pp = &channel->ch_close_partial; ! vim_free(*cbp); ! partial_unref(*pp); ! if (opt->jo_close_cb != NULL && *opt->jo_close_cb != NUL) ! *cbp = vim_strsave(opt->jo_close_cb); ! else ! *cbp = NULL; ! *pp = opt->jo_close_partial; ! if (*pp != NULL) ! ++(*pp)->pt_refcount; ! } if ((opt->jo_set & JO_OUT_IO) && opt->jo_io[PART_OUT] == JIO_BUFFER) { --- 1159,1177 ---- channel->ch_part[PART_IN].ch_block_write = 1; if (opt->jo_set & JO_CALLBACK) ! set_callback(&channel->ch_callback, &channel->ch_partial, ! opt->jo_callback, opt->jo_partial); if (opt->jo_set & JO_OUT_CALLBACK) ! set_callback(&channel->ch_part[PART_OUT].ch_callback, ! &channel->ch_part[PART_OUT].ch_partial, ! opt->jo_out_cb, opt->jo_out_partial); if (opt->jo_set & JO_ERR_CALLBACK) ! set_callback(&channel->ch_part[PART_ERR].ch_callback, ! &channel->ch_part[PART_ERR].ch_partial, ! opt->jo_err_cb, opt->jo_err_partial); if (opt->jo_set & JO_CLOSE_CALLBACK) ! set_callback(&channel->ch_close_cb, &channel->ch_close_partial, ! opt->jo_close_cb, opt->jo_close_partial); if ((opt->jo_set & JO_OUT_IO) && opt->jo_io[PART_OUT] == JIO_BUFFER) { *************** *** 2228,2235 **** * invokes ch_close() the list will be cleared. */ remove_cb_node(cbhead, item); invoke_callback(channel, item->cq_callback, item->cq_partial, argv); ! vim_free(item->cq_callback); ! partial_unref(item->cq_partial); vim_free(item); } --- 2201,2207 ---- * invokes ch_close() the list will be cleared. */ remove_cb_node(cbhead, item); invoke_callback(channel, item->cq_callback, item->cq_partial, argv); ! free_callback(item->cq_callback, item->cq_partial); vim_free(item); } *************** *** 2725,2733 **** } /* the callback is only called once */ ! vim_free(channel->ch_close_cb); channel->ch_close_cb = NULL; - partial_unref(channel->ch_close_partial); channel->ch_close_partial = NULL; --channel->ch_refcount; --- 2697,2704 ---- } /* the callback is only called once */ ! free_callback(channel->ch_close_cb, channel->ch_close_partial); channel->ch_close_cb = NULL; channel->ch_close_partial = NULL; --channel->ch_refcount; *************** *** 2763,2770 **** cbq_T *node = cb_head->cq_next; remove_cb_node(cb_head, node); ! vim_free(node->cq_callback); ! partial_unref(node->cq_partial); vim_free(node); } --- 2734,2740 ---- cbq_T *node = cb_head->cq_next; remove_cb_node(cb_head, node); ! free_callback(node->cq_callback, node->cq_partial); vim_free(node); } *************** *** 2774,2782 **** remove_json_node(json_head, json_head->jq_next); } ! vim_free(channel->ch_part[part].ch_callback); channel->ch_part[part].ch_callback = NULL; - partial_unref(channel->ch_part[part].ch_partial); channel->ch_part[part].ch_partial = NULL; } --- 2744,2752 ---- remove_json_node(json_head, json_head->jq_next); } ! free_callback(channel->ch_part[part].ch_callback, ! channel->ch_part[part].ch_partial); channel->ch_part[part].ch_callback = NULL; channel->ch_part[part].ch_partial = NULL; } *************** *** 2793,2805 **** channel_clear_one(channel, PART_OUT); channel_clear_one(channel, PART_ERR); /* there is no callback or queue for PART_IN */ ! vim_free(channel->ch_callback); channel->ch_callback = NULL; - partial_unref(channel->ch_partial); channel->ch_partial = NULL; ! vim_free(channel->ch_close_cb); channel->ch_close_cb = NULL; - partial_unref(channel->ch_close_partial); channel->ch_close_partial = NULL; } --- 2763,2773 ---- channel_clear_one(channel, PART_OUT); channel_clear_one(channel, PART_ERR); /* there is no callback or queue for PART_IN */ ! free_callback(channel->ch_callback, channel->ch_partial); channel->ch_callback = NULL; channel->ch_partial = NULL; ! free_callback(channel->ch_close_cb, channel->ch_close_partial); channel->ch_close_cb = NULL; channel->ch_close_partial = NULL; } *************** *** 4319,4326 **** mch_clear_job(job); vim_free(job->jv_stoponexit); ! vim_free(job->jv_exit_cb); ! partial_unref(job->jv_exit_partial); } static void --- 4287,4293 ---- mch_clear_job(job); vim_free(job->jv_stoponexit); ! free_callback(job->jv_exit_cb, job->jv_exit_partial); } static void *************** *** 4485,4492 **** } if (opt->jo_set & JO_EXIT_CB) { ! vim_free(job->jv_exit_cb); ! partial_unref(job->jv_exit_partial); if (opt->jo_exit_cb == NULL || *opt->jo_exit_cb == NUL) { job->jv_exit_cb = NULL; --- 4452,4458 ---- } if (opt->jo_set & JO_EXIT_CB) { ! free_callback(job->jv_exit_cb, job->jv_exit_partial); if (opt->jo_exit_cb == NULL || *opt->jo_exit_cb == NUL) { job->jv_exit_cb = NULL; *** ../vim-7.4.2025/src/eval.c 2016-07-10 22:11:11.862751461 +0200 --- src/eval.c 2016-07-11 22:36:52.976641709 +0200 *************** *** 21178,21190 **** return (*pp)->pt_name; } *pp = NULL; ! if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING) return arg->vval.v_string; if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0) return (char_u *)""; EMSG(_("E921: Invalid callback argument")); return NULL; } #endif #ifdef FEAT_TIMERS --- 21178,21210 ---- return (*pp)->pt_name; } *pp = NULL; ! if (arg->v_type == VAR_FUNC) ! { ! func_ref(arg->vval.v_string); ! return arg->vval.v_string; ! } ! if (arg->v_type == VAR_STRING) return arg->vval.v_string; if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0) return (char_u *)""; EMSG(_("E921: Invalid callback argument")); return NULL; } + + /* + * Unref/free "callback" and "partial" retured by get_callback(). + */ + void + free_callback(char_u *callback, partial_T *partial) + { + if (partial != NULL) + partial_unref(partial); + else if (callback != NULL) + { + func_unref(callback); + vim_free(callback); + } + } #endif #ifdef FEAT_TIMERS *** ../vim-7.4.2025/src/ex_cmds2.c 2016-07-10 22:11:11.862751461 +0200 --- src/ex_cmds2.c 2016-07-11 21:19:24.494478162 +0200 *************** *** 1121,1128 **** static void free_timer(timer_T *timer) { ! vim_free(timer->tr_callback); ! partial_unref(timer->tr_partial); vim_free(timer); } --- 1121,1127 ---- static void free_timer(timer_T *timer) { ! free_callback(timer->tr_callback, timer->tr_partial); vim_free(timer); } *** ../vim-7.4.2025/src/proto/eval.pro 2016-07-09 17:05:49.207222368 +0200 --- src/proto/eval.pro 2016-07-11 21:14:40.566748633 +0200 *************** *** 94,99 **** --- 94,100 ---- float_T vim_round(float_T f); long do_searchpair(char_u *spat, char_u *mpat, char_u *epat, int dir, char_u *skip, int flags, pos_T *match_pos, linenr_T lnum_stop, long time_limit); char_u *get_callback(typval_T *arg, partial_T **pp); + void free_callback(char_u *callback, partial_T *partial); void set_vim_var_nr(int idx, varnumber_T val); varnumber_T get_vim_var_nr(int idx); char_u *get_vim_var_str(int idx); *** ../vim-7.4.2025/src/version.c 2016-07-10 23:16:05.112753072 +0200 --- src/version.c 2016-07-11 21:16:41.752925492 +0200 *************** *** 760,761 **** --- 760,763 ---- { /* Add new patch number below this line */ + /**/ + 2026, /**/ -- We're knights of the round table We dance whene'er we're able We do routines and chorus scenes With footwork impeccable. We dine well here in Camelot We eat ham and jam and spam a lot. "Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///