Patch 7.4.1717
Problem:    Leaking memory when opening a channel fails.
Solution:   Unreference partials in job options.
Files:      src/eval.c, src/channel.c, src/proto/channel.pro,
            src/testdir/test_channel.vim


*** ../vim-7.4.1716/src/eval.c  2016-04-06 22:59:33.503226978 +0200
--- src/eval.c  2016-04-07 21:15:46.514517082 +0200
***************
*** 10321,10329 ****
        return;
      clear_job_options(&opt);
      if (get_job_options(&argvars[1], &opt,
!               JO_CB_ALL + JO_TIMEOUT_ALL + JO_MODE_ALL) == FAIL)
!       return;
!     channel_set_options(channel, &opt);
  }
  
  /*
--- 10321,10329 ----
        return;
      clear_job_options(&opt);
      if (get_job_options(&argvars[1], &opt,
!                             JO_CB_ALL + JO_TIMEOUT_ALL + JO_MODE_ALL) == OK)
!       channel_set_options(channel, &opt);
!     free_job_options(&opt);
  }
  
  /*
***************
*** 14889,14897 ****
      if (job == NULL)
        return;
      clear_job_options(&opt);
!     if (get_job_options(&argvars[1], &opt, JO_STOPONEXIT + JO_EXIT_CB) == 
FAIL)
!       return;
!     job_set_options(job, &opt);
  }
  
  /*
--- 14889,14897 ----
      if (job == NULL)
        return;
      clear_job_options(&opt);
!     if (get_job_options(&argvars[1], &opt, JO_STOPONEXIT + JO_EXIT_CB) == OK)
!       job_set_options(job, &opt);
!     free_job_options(&opt);
  }
  
  /*
*** ../vim-7.4.1716/src/channel.c       2016-03-30 21:06:53.723772030 +0200
--- src/channel.c       2016-04-07 21:16:18.230184688 +0200
***************
*** 858,864 ****
      char      *rest;
      int               port;
      jobopt_T    opt;
!     channel_T *channel;
  
      address = get_tv_string(&argvars[0]);
      if (argvars[1].v_type != VAR_UNKNOWN
--- 858,864 ----
      char      *rest;
      int               port;
      jobopt_T    opt;
!     channel_T *channel = NULL;
  
      address = get_tv_string(&argvars[0]);
      if (argvars[1].v_type != VAR_UNKNOWN
***************
*** 890,900 ****
      opt.jo_timeout = 2000;
      if (get_job_options(&argvars[1], &opt,
              JO_MODE_ALL + JO_CB_ALL + JO_WAITTIME + JO_TIMEOUT_ALL) == FAIL)
!       return NULL;
      if (opt.jo_timeout < 0)
      {
        EMSG(_(e_invarg));
!       return NULL;
      }
  
      channel = channel_open((char *)address, port, opt.jo_waittime, NULL);
--- 890,900 ----
      opt.jo_timeout = 2000;
      if (get_job_options(&argvars[1], &opt,
              JO_MODE_ALL + JO_CB_ALL + JO_WAITTIME + JO_TIMEOUT_ALL) == FAIL)
!       goto theend;
      if (opt.jo_timeout < 0)
      {
        EMSG(_(e_invarg));
!       goto theend;
      }
  
      channel = channel_open((char *)address, port, opt.jo_waittime, NULL);
***************
*** 903,908 ****
--- 903,910 ----
        opt.jo_set = JO_ALL;
        channel_set_options(channel, &opt);
      }
+ theend:
+     free_job_options(&opt);
      return channel;
  }
  
***************
*** 2897,2903 ****
      clear_job_options(&opt);
      if (get_job_options(&argvars[1], &opt, JO_TIMEOUT + JO_PART + JO_ID)
                                                                      == FAIL)
!       return;
  
      channel = get_channel_arg(&argvars[0], TRUE);
      if (channel != NULL)
--- 2899,2905 ----
      clear_job_options(&opt);
      if (get_job_options(&argvars[1], &opt, JO_TIMEOUT + JO_PART + JO_ID)
                                                                      == FAIL)
!       goto theend;
  
      channel = get_channel_arg(&argvars[0], TRUE);
      if (channel != NULL)
***************
*** 2930,2935 ****
--- 2932,2940 ----
            }
        }
      }
+ 
+ theend:
+     free_job_options(&opt);
  }
  
  # if defined(WIN32) || defined(FEAT_GUI_X11) || defined(FEAT_GUI_GTK) \
***************
*** 3056,3068 ****
      channel_T *channel;
      int               part_send;
  
      channel = get_channel_arg(&argvars[0], TRUE);
      if (channel == NULL)
        return NULL;
      part_send = channel_part_send(channel);
      *part_read = channel_part_read(channel);
  
-     clear_job_options(opt);
      if (get_job_options(&argvars[2], opt, JO_CALLBACK + JO_TIMEOUT) == FAIL)
        return NULL;
  
--- 3061,3073 ----
      channel_T *channel;
      int               part_send;
  
+     clear_job_options(opt);
      channel = get_channel_arg(&argvars[0], TRUE);
      if (channel == NULL)
        return NULL;
      part_send = channel_part_send(channel);
      *part_read = channel_part_read(channel);
  
      if (get_job_options(&argvars[2], opt, JO_CALLBACK + JO_TIMEOUT) == FAIL)
        return NULL;
  
***************
*** 3145,3150 ****
--- 3150,3156 ----
            free_tv(listtv);
        }
      }
+     free_job_options(&opt);
  }
  
  /*
***************
*** 3175,3180 ****
--- 3181,3187 ----
            timeout = channel_get_timeout(channel, part_read);
        rettv->vval.v_string = channel_read_block(channel, part_read, timeout);
      }
+     free_job_options(&opt);
  }
  
  # if (defined(UNIX) && !defined(HAVE_SELECT)) || defined(PROTO)
***************
*** 3545,3550 ****
--- 3552,3560 ----
      return OK;
  }
  
+ /*
+  * Clear a jobopt_T before using it.
+  */
      void
  clear_job_options(jobopt_T *opt)
  {
***************
*** 3552,3557 ****
--- 3562,3583 ----
  }
  
  /*
+  * Free any members of a jobopt_T.
+  */
+     void
+ free_job_options(jobopt_T *opt)
+ {
+     if (opt->jo_partial != NULL)
+       partial_unref(opt->jo_partial);
+     if (opt->jo_out_partial != NULL)
+       partial_unref(opt->jo_out_partial);
+     if (opt->jo_err_partial != NULL)
+       partial_unref(opt->jo_err_partial);
+     if (opt->jo_close_partial != NULL)
+       partial_unref(opt->jo_close_partial);
+ }
+ 
+ /*
   * Get the PART_ number from the first character of an option name.
   */
      static int
***************
*** 4053,4058 ****
--- 4079,4087 ----
        return NULL;
  
      job->jv_status = JOB_FAILED;
+ #ifndef USE_ARGV
+     ga_init2(&ga, (int)sizeof(char*), 20);
+ #endif
  
      /* Default mode is NL. */
      clear_job_options(&opt);
***************
*** 4060,4066 ****
      if (get_job_options(&argvars[1], &opt,
            JO_MODE_ALL + JO_CB_ALL + JO_TIMEOUT_ALL + JO_STOPONEXIT
                           + JO_EXIT_CB + JO_OUT_IO + JO_BLOCK_WRITE) == FAIL)
!       return job;
  
      /* Check that when io is "file" that there is a file name. */
      for (part = PART_OUT; part <= PART_IN; ++part)
--- 4089,4095 ----
      if (get_job_options(&argvars[1], &opt,
            JO_MODE_ALL + JO_CB_ALL + JO_TIMEOUT_ALL + JO_STOPONEXIT
                           + JO_EXIT_CB + JO_OUT_IO + JO_BLOCK_WRITE) == FAIL)
!       goto theend;
  
      /* Check that when io is "file" that there is a file name. */
      for (part = PART_OUT; part <= PART_IN; ++part)
***************
*** 4070,4076 ****
                    || *opt.jo_io_name[part] == NUL))
        {
            EMSG(_("E920: _io file requires _name to be set"));
!           return job;
        }
  
      if ((opt.jo_set & JO_IN_IO) && opt.jo_io[PART_IN] == JIO_BUFFER)
--- 4099,4105 ----
                    || *opt.jo_io_name[part] == NUL))
        {
            EMSG(_("E920: _io file requires _name to be set"));
!           goto theend;
        }
  
      if ((opt.jo_set & JO_IN_IO) && opt.jo_io[PART_IN] == JIO_BUFFER)
***************
*** 4091,4097 ****
        else
            buf = buflist_find_by_name(opt.jo_io_name[PART_IN], FALSE);
        if (buf == NULL)
!           return job;
        if (buf->b_ml.ml_mfp == NULL)
        {
            char_u      numbuf[NUMBUFLEN];
--- 4120,4126 ----
        else
            buf = buflist_find_by_name(opt.jo_io_name[PART_IN], FALSE);
        if (buf == NULL)
!           goto theend;
        if (buf->b_ml.ml_mfp == NULL)
        {
            char_u      numbuf[NUMBUFLEN];
***************
*** 4105,4121 ****
            else
                s = opt.jo_io_name[PART_IN];
            EMSG2(_("E918: buffer must be loaded: %s"), s);
!           return job;
        }
        job->jv_in_buf = buf;
      }
  
      job_set_options(job, &opt);
  
- #ifndef USE_ARGV
-     ga_init2(&ga, (int)sizeof(char*), 20);
- #endif
- 
      if (argvars[0].v_type == VAR_STRING)
      {
        /* Command is a string. */
--- 4134,4146 ----
            else
                s = opt.jo_io_name[PART_IN];
            EMSG2(_("E918: buffer must be loaded: %s"), s);
!           goto theend;
        }
        job->jv_in_buf = buf;
      }
  
      job_set_options(job, &opt);
  
      if (argvars[0].v_type == VAR_STRING)
      {
        /* Command is a string. */
***************
*** 4123,4133 ****
        if (cmd == NULL || *cmd == NUL)
        {
            EMSG(_(e_invarg));
!           return job;
        }
  #ifdef USE_ARGV
        if (mch_parse_cmd(cmd, FALSE, &argv, &argc) == FAIL)
!           return job;
        argv[argc] = NULL;
  #endif
      }
--- 4148,4158 ----
        if (cmd == NULL || *cmd == NUL)
        {
            EMSG(_(e_invarg));
!           goto theend;
        }
  #ifdef USE_ARGV
        if (mch_parse_cmd(cmd, FALSE, &argv, &argc) == FAIL)
!           goto theend;
        argv[argc] = NULL;
  #endif
      }
***************
*** 4136,4142 ****
            || argvars[0].vval.v_list->lv_len < 1)
      {
        EMSG(_(e_invarg));
!       return job;
      }
      else
      {
--- 4161,4167 ----
            || argvars[0].vval.v_list->lv_len < 1)
      {
        EMSG(_(e_invarg));
!       goto theend;
      }
      else
      {
***************
*** 4148,4154 ****
        /* Pass argv[] to mch_call_shell(). */
        argv = (char **)alloc(sizeof(char *) * (l->lv_len + 1));
        if (argv == NULL)
!           return job;
  #endif
        for (li = l->lv_first; li != NULL; li = li->li_next)
        {
--- 4173,4179 ----
        /* Pass argv[] to mch_call_shell(). */
        argv = (char **)alloc(sizeof(char *) * (l->lv_len + 1));
        if (argv == NULL)
!           goto theend;
  #endif
        for (li = l->lv_first; li != NULL; li = li->li_next)
        {
***************
*** 4222,4227 ****
--- 4247,4253 ----
  #else
      vim_free(ga.ga_data);
  #endif
+     free_job_options(&opt);
      return job;
  }
  
*** ../vim-7.4.1716/src/proto/channel.pro       2016-03-28 19:16:15.669846492 
+0200
--- src/proto/channel.pro       2016-04-07 21:16:38.017977325 +0200
***************
*** 46,51 ****
--- 46,52 ----
  ch_mode_T channel_get_mode(channel_T *channel, int part);
  int channel_get_timeout(channel_T *channel, int part);
  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);
  void job_unref(job_T *job);
*** ../vim-7.4.1716/src/testdir/test_channel.vim        2016-03-30 
21:06:53.723772030 +0200
--- src/testdir/test_channel.vim        2016-04-07 21:07:30.883739433 +0200
***************
*** 1231,1235 ****
--- 1231,1247 ----
    call assert_fails('call job_start("")', 'E474:')
  endfunc
  
+ " This leaking memory.
+ func Test_partial_in_channel_cycle()
+   let d = {}
+   let d.a = function('string', [d])
+   try
+     let d.b = ch_open('nowhere:123', {'close_cb': d.a})
+   catch
+     call assert_exception('E901:')
+   endtry
+   unlet d
+ endfunc
+ 
  " Uncomment this to see what happens, output is in src/testdir/channellog.
  " call ch_logfile('channellog', 'w')
*** ../vim-7.4.1716/src/version.c       2016-04-06 23:06:18.590052451 +0200
--- src/version.c       2016-04-07 21:38:15.284413842 +0200
***************
*** 750,751 ****
--- 750,753 ----
  {   /* Add new patch number below this line */
+ /**/
+     1717,
  /**/

-- 
hundred-and-one symptoms of being an internet addict:
242. You turn down a better-paying job because it doesn't come with
     a free e-mail account.

 /// Bram Moolenaar -- [email protected] -- 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    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Raspunde prin e-mail lui