Patch 8.0.0297
Problem:    Double free on exit when using a closure. (James McCoy)
Solution:   Split free_al_functions in two parts. (closes #1428)
Files:      src/userfunc.c, src/structs.h


*** ../vim-8.0.0296/src/userfunc.c      2017-02-01 20:26:45.769640496 +0100
--- src/userfunc.c      2017-02-02 22:56:09.536572550 +0100
***************
*** 1075,1086 ****
  }
  
  /*
!  * Free a function and remove it from the list of functions.
   * When "force" is TRUE we are exiting.
   */
      static void
! func_free(ufunc_T *fp, int force)
  {
      /* clear this function */
      ga_clear_strings(&(fp->uf_args));
      ga_clear_strings(&(fp->uf_lines));
--- 1075,1091 ----
  }
  
  /*
!  * Free all things that a function contains.  Does not free the function
!  * itself, use func_free() for that.
   * When "force" is TRUE we are exiting.
   */
      static void
! func_clear(ufunc_T *fp, int force)
  {
+     if (fp->uf_cleared)
+       return;
+     fp->uf_cleared = TRUE;
+ 
      /* clear this function */
      ga_clear_strings(&(fp->uf_args));
      ga_clear_strings(&(fp->uf_lines));
***************
*** 1089,1105 ****
      vim_free(fp->uf_tml_total);
      vim_free(fp->uf_tml_self);
  #endif
      /* only remove it when not done already, otherwise we would remove a newer
       * version of the function */
      if ((fp->uf_flags & (FC_DELETED | FC_REMOVED)) == 0)
        func_remove(fp);
  
-     funccal_unref(fp->uf_scoped, fp, force);
- 
      vim_free(fp);
  }
  
  /*
   * There are two kinds of function names:
   * 1. ordinary names, function defined with :function
   * 2. numbered functions and lambdas
--- 1094,1129 ----
      vim_free(fp->uf_tml_total);
      vim_free(fp->uf_tml_self);
  #endif
+     funccal_unref(fp->uf_scoped, fp, force);
+ }
+ 
+ /*
+  * Free a function and remove it from the list of functions.  Does not free
+  * what a function contains, call func_clear() first.
+  */
+     static void
+ func_free(ufunc_T *fp)
+ {
      /* only remove it when not done already, otherwise we would remove a newer
       * version of the function */
      if ((fp->uf_flags & (FC_DELETED | FC_REMOVED)) == 0)
        func_remove(fp);
  
      vim_free(fp);
  }
  
  /*
+  * Free all things that a function contains and free the function itself.
+  * When "force" is TRUE we are exiting.
+  */
+     static void
+ func_clear_free(ufunc_T *fp, int force)
+ {
+     func_clear(fp, force);
+     func_free(fp);
+ }
+ 
+ /*
   * There are two kinds of function names:
   * 1. ordinary names, function defined with :function
   * 2. numbered functions and lambdas
***************
*** 1120,1129 ****
      hashitem_T        *hi;
      ufunc_T   *fp;
      long_u    skipped = 0;
!     long_u    todo;
  
!     /* Need to start all over every time, because func_free() may change the
!      * hash table. */
      while (func_hashtab.ht_used > skipped)
      {
        todo = func_hashtab.ht_used;
--- 1144,1183 ----
      hashitem_T        *hi;
      ufunc_T   *fp;
      long_u    skipped = 0;
!     long_u    todo = 1;
!     long_u    used;
! 
!     /* First clear what the functions contain.  Since this may lower the
!      * reference count of a function, it may also free a function and change
!      * the hash table. Restart if that happens. */
!     while (todo > 0)
!     {
!       todo = func_hashtab.ht_used;
!       for (hi = func_hashtab.ht_array; todo > 0; ++hi)
!           if (!HASHITEM_EMPTY(hi))
!           {
!               /* Only free functions that are not refcounted, those are
!                * supposed to be freed when no longer referenced. */
!               fp = HI2UF(hi);
!               if (func_name_refcount(fp->uf_name))
!                   ++skipped;
!               else
!               {
!                   used = func_hashtab.ht_used;
!                   func_clear(fp, TRUE);
!                   if (used != func_hashtab.ht_used)
!                   {
!                       skipped = 0;
!                       break;
!                   }
!               }
!               --todo;
!           }
!     }
  
!     /* Now actually free the functions.  Need to start all over every time,
!      * because func_free() may change the hash table. */
!     skipped = 0;
      while (func_hashtab.ht_used > skipped)
      {
        todo = func_hashtab.ht_used;
***************
*** 1138,1144 ****
                    ++skipped;
                else
                {
!                   func_free(fp, TRUE);
                    skipped = 0;
                    break;
                }
--- 1192,1198 ----
                    ++skipped;
                else
                {
!                   func_free(fp);
                    skipped = 0;
                    break;
                }
***************
*** 1356,1362 ****
                    if (--fp->uf_calls <= 0 && fp->uf_refcount <= 0)
                        /* Function was unreferenced while being used, free it
                         * now. */
!                       func_free(fp, FALSE);
                    if (did_save_redo)
                        restoreRedobuff();
                    restore_search_patterns();
--- 1410,1416 ----
                    if (--fp->uf_calls <= 0 && fp->uf_refcount <= 0)
                        /* Function was unreferenced while being used, free it
                         * now. */
!                       func_clear_free(fp, FALSE);
                    if (did_save_redo)
                        restoreRedobuff();
                    restore_search_patterns();
***************
*** 2756,2762 ****
                fp->uf_flags |= FC_DELETED;
            }
            else
!               func_free(fp, FALSE);
        }
      }
  }
--- 2810,2816 ----
                fp->uf_flags |= FC_DELETED;
            }
            else
!               func_clear_free(fp, FALSE);
        }
      }
  }
***************
*** 2785,2791 ****
        /* Only delete it when it's not being used.  Otherwise it's done
         * when "uf_calls" becomes zero. */
        if (fp->uf_calls == 0)
!           func_free(fp, FALSE);
      }
  }
  
--- 2839,2845 ----
        /* Only delete it when it's not being used.  Otherwise it's done
         * when "uf_calls" becomes zero. */
        if (fp->uf_calls == 0)
!           func_clear_free(fp, FALSE);
      }
  }
  
***************
*** 2801,2807 ****
        /* Only delete it when it's not being used.  Otherwise it's done
         * when "uf_calls" becomes zero. */
        if (fp->uf_calls == 0)
!           func_free(fp, FALSE);
      }
  }
  
--- 2855,2861 ----
        /* Only delete it when it's not being used.  Otherwise it's done
         * when "uf_calls" becomes zero. */
        if (fp->uf_calls == 0)
!           func_clear_free(fp, FALSE);
      }
  }
  
*** ../vim-8.0.0296/src/structs.h       2017-01-22 18:34:53.684030783 +0100
--- src/structs.h       2017-02-02 22:44:38.069397093 +0100
***************
*** 1337,1342 ****
--- 1337,1343 ----
      int               uf_varargs;     /* variable nr of arguments */
      int               uf_flags;
      int               uf_calls;       /* nr of active calls */
+     int               uf_cleared;     /* func_clear() was already called */
      garray_T  uf_args;        /* arguments */
      garray_T  uf_lines;       /* function lines */
  #ifdef FEAT_PROFILE
*** ../vim-8.0.0296/src/version.c       2017-02-02 22:20:49.279397163 +0100
--- src/version.c       2017-02-02 22:44:52.229298214 +0100
***************
*** 766,767 ****
--- 766,769 ----
  {   /* Add new patch number below this line */
+ /**/
+     297,
  /**/

-- 
There is no right or wrong, there is only your personal opinion.
                 (Bram Moolenaar)

 /// 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