Karsten Hopp 634b72
To: vim_dev@googlegroups.com
Karsten Hopp 634b72
Subject: Patch 7.3.055
Karsten Hopp 634b72
Fcc: outbox
Karsten Hopp 634b72
From: Bram Moolenaar <Bram@moolenaar.net>
Karsten Hopp 634b72
Mime-Version: 1.0
Karsten Hopp 634b72
Content-Type: text/plain; charset=UTF-8
Karsten Hopp 634b72
Content-Transfer-Encoding: 8bit
Karsten Hopp 634b72
------------
Karsten Hopp 634b72
Karsten Hopp 634b72
Patch 7.3.055
Karsten Hopp 634b72
Problem:    Recursively nested lists and dictionaries cause a near-endless
Karsten Hopp 634b72
	    loop when comparing them with a copy. (ZyX)
Karsten Hopp 634b72
Solution:   Limit recursiveness in a way that non-recursive structures can
Karsten Hopp 634b72
	    still be nested very deep.
Karsten Hopp 634b72
Files:	    src/eval.c, src/testdir/test55.in, src/testdir/test55.ok
Karsten Hopp 634b72
Karsten Hopp 634b72
Karsten Hopp 634b72
*** ../vim-7.3.054/src/eval.c	2010-10-20 21:22:17.000000000 +0200
Karsten Hopp 634b72
--- src/eval.c	2010-11-10 20:02:57.000000000 +0100
Karsten Hopp 634b72
***************
Karsten Hopp 634b72
*** 434,442 ****
Karsten Hopp 634b72
  static void listitem_free __ARGS((listitem_T *item));
Karsten Hopp 634b72
  static void listitem_remove __ARGS((list_T *l, listitem_T *item));
Karsten Hopp 634b72
  static long list_len __ARGS((list_T *l));
Karsten Hopp 634b72
! static int list_equal __ARGS((list_T *l1, list_T *l2, int ic));
Karsten Hopp 634b72
! static int dict_equal __ARGS((dict_T *d1, dict_T *d2, int ic));
Karsten Hopp 634b72
! static int tv_equal __ARGS((typval_T *tv1, typval_T *tv2, int ic));
Karsten Hopp 634b72
  static listitem_T *list_find __ARGS((list_T *l, long n));
Karsten Hopp 634b72
  static long list_find_nr __ARGS((list_T *l, long idx, int *errorp));
Karsten Hopp 634b72
  static long list_idx_of_item __ARGS((list_T *l, listitem_T *item));
Karsten Hopp 634b72
--- 434,442 ----
Karsten Hopp 634b72
  static void listitem_free __ARGS((listitem_T *item));
Karsten Hopp 634b72
  static void listitem_remove __ARGS((list_T *l, listitem_T *item));
Karsten Hopp 634b72
  static long list_len __ARGS((list_T *l));
Karsten Hopp 634b72
! static int list_equal __ARGS((list_T *l1, list_T *l2, int ic, int recursive));
Karsten Hopp 634b72
! static int dict_equal __ARGS((dict_T *d1, dict_T *d2, int ic, int recursive));
Karsten Hopp 634b72
! static int tv_equal __ARGS((typval_T *tv1, typval_T *tv2, int ic, int recursive));
Karsten Hopp 634b72
  static listitem_T *list_find __ARGS((list_T *l, long n));
Karsten Hopp 634b72
  static long list_find_nr __ARGS((list_T *l, long idx, int *errorp));
Karsten Hopp 634b72
  static long list_idx_of_item __ARGS((list_T *l, listitem_T *item));
Karsten Hopp 634b72
***************
Karsten Hopp 634b72
*** 4350,4356 ****
Karsten Hopp 634b72
  		else
Karsten Hopp 634b72
  		{
Karsten Hopp 634b72
  		    /* Compare two Lists for being equal or unequal. */
Karsten Hopp 634b72
! 		    n1 = list_equal(rettv->vval.v_list, var2.vval.v_list, ic);
Karsten Hopp 634b72
  		    if (type == TYPE_NEQUAL)
Karsten Hopp 634b72
  			n1 = !n1;
Karsten Hopp 634b72
  		}
Karsten Hopp 634b72
--- 4350,4357 ----
Karsten Hopp 634b72
  		else
Karsten Hopp 634b72
  		{
Karsten Hopp 634b72
  		    /* Compare two Lists for being equal or unequal. */
Karsten Hopp 634b72
! 		    n1 = list_equal(rettv->vval.v_list, var2.vval.v_list,
Karsten Hopp 634b72
! 								   ic, FALSE);
Karsten Hopp 634b72
  		    if (type == TYPE_NEQUAL)
Karsten Hopp 634b72
  			n1 = !n1;
Karsten Hopp 634b72
  		}
Karsten Hopp 634b72
***************
Karsten Hopp 634b72
*** 4379,4385 ****
Karsten Hopp 634b72
  		else
Karsten Hopp 634b72
  		{
Karsten Hopp 634b72
  		    /* Compare two Dictionaries for being equal or unequal. */
Karsten Hopp 634b72
! 		    n1 = dict_equal(rettv->vval.v_dict, var2.vval.v_dict, ic);
Karsten Hopp 634b72
  		    if (type == TYPE_NEQUAL)
Karsten Hopp 634b72
  			n1 = !n1;
Karsten Hopp 634b72
  		}
Karsten Hopp 634b72
--- 4380,4387 ----
Karsten Hopp 634b72
  		else
Karsten Hopp 634b72
  		{
Karsten Hopp 634b72
  		    /* Compare two Dictionaries for being equal or unequal. */
Karsten Hopp 634b72
! 		    n1 = dict_equal(rettv->vval.v_dict, var2.vval.v_dict,
Karsten Hopp 634b72
! 								   ic, FALSE);
Karsten Hopp 634b72
  		    if (type == TYPE_NEQUAL)
Karsten Hopp 634b72
  			n1 = !n1;
Karsten Hopp 634b72
  		}
Karsten Hopp 634b72
***************
Karsten Hopp 634b72
*** 5914,5923 ****
Karsten Hopp 634b72
   * Return TRUE when two lists have exactly the same values.
Karsten Hopp 634b72
   */
Karsten Hopp 634b72
      static int
Karsten Hopp 634b72
! list_equal(l1, l2, ic)
Karsten Hopp 634b72
      list_T	*l1;
Karsten Hopp 634b72
      list_T	*l2;
Karsten Hopp 634b72
      int		ic;	/* ignore case for strings */
Karsten Hopp 634b72
  {
Karsten Hopp 634b72
      listitem_T	*item1, *item2;
Karsten Hopp 634b72
  
Karsten Hopp 634b72
--- 5916,5926 ----
Karsten Hopp 634b72
   * Return TRUE when two lists have exactly the same values.
Karsten Hopp 634b72
   */
Karsten Hopp 634b72
      static int
Karsten Hopp 634b72
! list_equal(l1, l2, ic, recursive)
Karsten Hopp 634b72
      list_T	*l1;
Karsten Hopp 634b72
      list_T	*l2;
Karsten Hopp 634b72
      int		ic;	/* ignore case for strings */
Karsten Hopp 634b72
+     int		recursive;  /* TRUE when used recursively */
Karsten Hopp 634b72
  {
Karsten Hopp 634b72
      listitem_T	*item1, *item2;
Karsten Hopp 634b72
  
Karsten Hopp 634b72
***************
Karsten Hopp 634b72
*** 5931,5937 ****
Karsten Hopp 634b72
      for (item1 = l1->lv_first, item2 = l2->lv_first;
Karsten Hopp 634b72
  	    item1 != NULL && item2 != NULL;
Karsten Hopp 634b72
  			       item1 = item1->li_next, item2 = item2->li_next)
Karsten Hopp 634b72
! 	if (!tv_equal(&item1->li_tv, &item2->li_tv, ic))
Karsten Hopp 634b72
  	    return FALSE;
Karsten Hopp 634b72
      return item1 == NULL && item2 == NULL;
Karsten Hopp 634b72
  }
Karsten Hopp 634b72
--- 5934,5940 ----
Karsten Hopp 634b72
      for (item1 = l1->lv_first, item2 = l2->lv_first;
Karsten Hopp 634b72
  	    item1 != NULL && item2 != NULL;
Karsten Hopp 634b72
  			       item1 = item1->li_next, item2 = item2->li_next)
Karsten Hopp 634b72
! 	if (!tv_equal(&item1->li_tv, &item2->li_tv, ic, recursive))
Karsten Hopp 634b72
  	    return FALSE;
Karsten Hopp 634b72
      return item1 == NULL && item2 == NULL;
Karsten Hopp 634b72
  }
Karsten Hopp 634b72
***************
Karsten Hopp 634b72
*** 5953,5962 ****
Karsten Hopp 634b72
   * Return TRUE when two dictionaries have exactly the same key/values.
Karsten Hopp 634b72
   */
Karsten Hopp 634b72
      static int
Karsten Hopp 634b72
! dict_equal(d1, d2, ic)
Karsten Hopp 634b72
      dict_T	*d1;
Karsten Hopp 634b72
      dict_T	*d2;
Karsten Hopp 634b72
      int		ic;	/* ignore case for strings */
Karsten Hopp 634b72
  {
Karsten Hopp 634b72
      hashitem_T	*hi;
Karsten Hopp 634b72
      dictitem_T	*item2;
Karsten Hopp 634b72
--- 5956,5966 ----
Karsten Hopp 634b72
   * Return TRUE when two dictionaries have exactly the same key/values.
Karsten Hopp 634b72
   */
Karsten Hopp 634b72
      static int
Karsten Hopp 634b72
! dict_equal(d1, d2, ic, recursive)
Karsten Hopp 634b72
      dict_T	*d1;
Karsten Hopp 634b72
      dict_T	*d2;
Karsten Hopp 634b72
      int		ic;	/* ignore case for strings */
Karsten Hopp 634b72
+     int		recursive; /* TRUE when used recursively */
Karsten Hopp 634b72
  {
Karsten Hopp 634b72
      hashitem_T	*hi;
Karsten Hopp 634b72
      dictitem_T	*item2;
Karsten Hopp 634b72
***************
Karsten Hopp 634b72
*** 5977,5983 ****
Karsten Hopp 634b72
  	    item2 = dict_find(d2, hi->hi_key, -1);
Karsten Hopp 634b72
  	    if (item2 == NULL)
Karsten Hopp 634b72
  		return FALSE;
Karsten Hopp 634b72
! 	    if (!tv_equal(&HI2DI(hi)->di_tv, &item2->di_tv, ic))
Karsten Hopp 634b72
  		return FALSE;
Karsten Hopp 634b72
  	    --todo;
Karsten Hopp 634b72
  	}
Karsten Hopp 634b72
--- 5981,5987 ----
Karsten Hopp 634b72
  	    item2 = dict_find(d2, hi->hi_key, -1);
Karsten Hopp 634b72
  	    if (item2 == NULL)
Karsten Hopp 634b72
  		return FALSE;
Karsten Hopp 634b72
! 	    if (!tv_equal(&HI2DI(hi)->di_tv, &item2->di_tv, ic, recursive))
Karsten Hopp 634b72
  		return FALSE;
Karsten Hopp 634b72
  	    --todo;
Karsten Hopp 634b72
  	}
Karsten Hopp 634b72
***************
Karsten Hopp 634b72
*** 5985,6025 ****
Karsten Hopp 634b72
      return TRUE;
Karsten Hopp 634b72
  }
Karsten Hopp 634b72
  
Karsten Hopp 634b72
  /*
Karsten Hopp 634b72
   * Return TRUE if "tv1" and "tv2" have the same value.
Karsten Hopp 634b72
   * Compares the items just like "==" would compare them, but strings and
Karsten Hopp 634b72
   * numbers are different.  Floats and numbers are also different.
Karsten Hopp 634b72
   */
Karsten Hopp 634b72
      static int
Karsten Hopp 634b72
! tv_equal(tv1, tv2, ic)
Karsten Hopp 634b72
      typval_T *tv1;
Karsten Hopp 634b72
      typval_T *tv2;
Karsten Hopp 634b72
!     int	    ic;	    /* ignore case */
Karsten Hopp 634b72
  {
Karsten Hopp 634b72
      char_u	buf1[NUMBUFLEN], buf2[NUMBUFLEN];
Karsten Hopp 634b72
      char_u	*s1, *s2;
Karsten Hopp 634b72
!     static int  recursive = 0;	    /* cach recursive loops */
Karsten Hopp 634b72
      int		r;
Karsten Hopp 634b72
  
Karsten Hopp 634b72
      if (tv1->v_type != tv2->v_type)
Karsten Hopp 634b72
  	return FALSE;
Karsten Hopp 634b72
      /* Catch lists and dicts that have an endless loop by limiting
Karsten Hopp 634b72
!      * recursiveness to 1000.  We guess they are equal then. */
Karsten Hopp 634b72
!     if (recursive >= 1000)
Karsten Hopp 634b72
  	return TRUE;
Karsten Hopp 634b72
  
Karsten Hopp 634b72
      switch (tv1->v_type)
Karsten Hopp 634b72
      {
Karsten Hopp 634b72
  	case VAR_LIST:
Karsten Hopp 634b72
! 	    ++recursive;
Karsten Hopp 634b72
! 	    r = list_equal(tv1->vval.v_list, tv2->vval.v_list, ic);
Karsten Hopp 634b72
! 	    --recursive;
Karsten Hopp 634b72
  	    return r;
Karsten Hopp 634b72
  
Karsten Hopp 634b72
  	case VAR_DICT:
Karsten Hopp 634b72
! 	    ++recursive;
Karsten Hopp 634b72
! 	    r = dict_equal(tv1->vval.v_dict, tv2->vval.v_dict, ic);
Karsten Hopp 634b72
! 	    --recursive;
Karsten Hopp 634b72
  	    return r;
Karsten Hopp 634b72
  
Karsten Hopp 634b72
  	case VAR_FUNC:
Karsten Hopp 634b72
--- 5989,6042 ----
Karsten Hopp 634b72
      return TRUE;
Karsten Hopp 634b72
  }
Karsten Hopp 634b72
  
Karsten Hopp 634b72
+ static int tv_equal_recurse_limit;
Karsten Hopp 634b72
+ 
Karsten Hopp 634b72
  /*
Karsten Hopp 634b72
   * Return TRUE if "tv1" and "tv2" have the same value.
Karsten Hopp 634b72
   * Compares the items just like "==" would compare them, but strings and
Karsten Hopp 634b72
   * numbers are different.  Floats and numbers are also different.
Karsten Hopp 634b72
   */
Karsten Hopp 634b72
      static int
Karsten Hopp 634b72
! tv_equal(tv1, tv2, ic, recursive)
Karsten Hopp 634b72
      typval_T *tv1;
Karsten Hopp 634b72
      typval_T *tv2;
Karsten Hopp 634b72
!     int	     ic;	    /* ignore case */
Karsten Hopp 634b72
!     int	     recursive;	    /* TRUE when used recursively */
Karsten Hopp 634b72
  {
Karsten Hopp 634b72
      char_u	buf1[NUMBUFLEN], buf2[NUMBUFLEN];
Karsten Hopp 634b72
      char_u	*s1, *s2;
Karsten Hopp 634b72
!     static int  recursive_cnt = 0;	    /* catch recursive loops */
Karsten Hopp 634b72
      int		r;
Karsten Hopp 634b72
  
Karsten Hopp 634b72
      if (tv1->v_type != tv2->v_type)
Karsten Hopp 634b72
  	return FALSE;
Karsten Hopp 634b72
+ 
Karsten Hopp 634b72
      /* Catch lists and dicts that have an endless loop by limiting
Karsten Hopp 634b72
!      * recursiveness to a limit.  We guess they are equal then.
Karsten Hopp 634b72
!      * A fixed limit has the problem of still taking an awful long time.
Karsten Hopp 634b72
!      * Reduce the limit every time running into it. That should work fine for
Karsten Hopp 634b72
!      * deeply linked structures that are not recursively linked and catch
Karsten Hopp 634b72
!      * recursiveness quickly. */
Karsten Hopp 634b72
!     if (!recursive)
Karsten Hopp 634b72
! 	tv_equal_recurse_limit = 1000;
Karsten Hopp 634b72
!     if (recursive_cnt >= tv_equal_recurse_limit)
Karsten Hopp 634b72
!     {
Karsten Hopp 634b72
! 	--tv_equal_recurse_limit;
Karsten Hopp 634b72
  	return TRUE;
Karsten Hopp 634b72
+     }
Karsten Hopp 634b72
  
Karsten Hopp 634b72
      switch (tv1->v_type)
Karsten Hopp 634b72
      {
Karsten Hopp 634b72
  	case VAR_LIST:
Karsten Hopp 634b72
! 	    ++recursive_cnt;
Karsten Hopp 634b72
! 	    r = list_equal(tv1->vval.v_list, tv2->vval.v_list, ic, TRUE);
Karsten Hopp 634b72
! 	    --recursive_cnt;
Karsten Hopp 634b72
  	    return r;
Karsten Hopp 634b72
  
Karsten Hopp 634b72
  	case VAR_DICT:
Karsten Hopp 634b72
! 	    ++recursive_cnt;
Karsten Hopp 634b72
! 	    r = dict_equal(tv1->vval.v_dict, tv2->vval.v_dict, ic, TRUE);
Karsten Hopp 634b72
! 	    --recursive_cnt;
Karsten Hopp 634b72
  	    return r;
Karsten Hopp 634b72
  
Karsten Hopp 634b72
  	case VAR_FUNC:
Karsten Hopp 634b72
***************
Karsten Hopp 634b72
*** 9391,9397 ****
Karsten Hopp 634b72
  	    }
Karsten Hopp 634b72
  
Karsten Hopp 634b72
  	    for ( ; li != NULL; li = li->li_next)
Karsten Hopp 634b72
! 		if (tv_equal(&li->li_tv, &argvars[1], ic))
Karsten Hopp 634b72
  		    ++n;
Karsten Hopp 634b72
  	}
Karsten Hopp 634b72
      }
Karsten Hopp 634b72
--- 9408,9414 ----
Karsten Hopp 634b72
  	    }
Karsten Hopp 634b72
  
Karsten Hopp 634b72
  	    for ( ; li != NULL; li = li->li_next)
Karsten Hopp 634b72
! 		if (tv_equal(&li->li_tv, &argvars[1], ic, FALSE))
Karsten Hopp 634b72
  		    ++n;
Karsten Hopp 634b72
  	}
Karsten Hopp 634b72
      }
Karsten Hopp 634b72
***************
Karsten Hopp 634b72
*** 9418,9424 ****
Karsten Hopp 634b72
  		if (!HASHITEM_EMPTY(hi))
Karsten Hopp 634b72
  		{
Karsten Hopp 634b72
  		    --todo;
Karsten Hopp 634b72
! 		    if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic))
Karsten Hopp 634b72
  			++n;
Karsten Hopp 634b72
  		}
Karsten Hopp 634b72
  	    }
Karsten Hopp 634b72
--- 9435,9441 ----
Karsten Hopp 634b72
  		if (!HASHITEM_EMPTY(hi))
Karsten Hopp 634b72
  		{
Karsten Hopp 634b72
  		    --todo;
Karsten Hopp 634b72
! 		    if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic, FALSE))
Karsten Hopp 634b72
  			++n;
Karsten Hopp 634b72
  		}
Karsten Hopp 634b72
  	    }
Karsten Hopp 634b72
***************
Karsten Hopp 634b72
*** 12574,12580 ****
Karsten Hopp 634b72
  	}
Karsten Hopp 634b72
  
Karsten Hopp 634b72
  	for ( ; item != NULL; item = item->li_next, ++idx)
Karsten Hopp 634b72
! 	    if (tv_equal(&item->li_tv, &argvars[1], ic))
Karsten Hopp 634b72
  	    {
Karsten Hopp 634b72
  		rettv->vval.v_number = idx;
Karsten Hopp 634b72
  		break;
Karsten Hopp 634b72
--- 12591,12597 ----
Karsten Hopp 634b72
  	}
Karsten Hopp 634b72
  
Karsten Hopp 634b72
  	for ( ; item != NULL; item = item->li_next, ++idx)
Karsten Hopp 634b72
! 	    if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
Karsten Hopp 634b72
  	    {
Karsten Hopp 634b72
  		rettv->vval.v_number = idx;
Karsten Hopp 634b72
  		break;
Karsten Hopp 634b72
*** ../vim-7.3.054/src/testdir/test55.in	2010-08-15 21:57:29.000000000 +0200
Karsten Hopp 634b72
--- src/testdir/test55.in	2010-11-10 20:15:27.000000000 +0100
Karsten Hopp 634b72
***************
Karsten Hopp 634b72
*** 342,348 ****
Karsten Hopp 634b72
--- 342,359 ----
Karsten Hopp 634b72
  :$put =(d == d)
Karsten Hopp 634b72
  :$put =(l != deepcopy(l))
Karsten Hopp 634b72
  :$put =(d != deepcopy(d))
Karsten Hopp 634b72
+ :"
Karsten Hopp 634b72
+ :" compare complex recursively linked list and dict
Karsten Hopp 634b72
+ :let l = []
Karsten Hopp 634b72
+ :call add(l, l)
Karsten Hopp 634b72
+ :let dict4 = {"l": l}
Karsten Hopp 634b72
+ :call add(dict4.l, dict4)
Karsten Hopp 634b72
+ :let lcopy = deepcopy(l)
Karsten Hopp 634b72
+ :let dict4copy = deepcopy(dict4)
Karsten Hopp 634b72
+ :$put =(l == lcopy)
Karsten Hopp 634b72
+ :$put =(dict4 == dict4copy)
Karsten Hopp 634b72
  :endfun
Karsten Hopp 634b72
+ :"
Karsten Hopp 634b72
  :call Test(1, 2, [3, 4], {5: 6})  " This may take a while
Karsten Hopp 634b72
  :"
Karsten Hopp 634b72
  :delfunc Test
Karsten Hopp 634b72
*** ../vim-7.3.054/src/testdir/test55.ok	2010-08-15 21:57:29.000000000 +0200
Karsten Hopp 634b72
--- src/testdir/test55.ok	2010-11-10 20:16:37.000000000 +0100
Karsten Hopp 634b72
***************
Karsten Hopp 634b72
*** 109,111 ****
Karsten Hopp 634b72
--- 109,113 ----
Karsten Hopp 634b72
  1
Karsten Hopp 634b72
  0
Karsten Hopp 634b72
  0
Karsten Hopp 634b72
+ 1
Karsten Hopp 634b72
+ 1
Karsten Hopp 634b72
*** ../vim-7.3.054/src/version.c	2010-11-10 18:59:50.000000000 +0100
Karsten Hopp 634b72
--- src/version.c	2010-11-10 20:10:51.000000000 +0100
Karsten Hopp 634b72
***************
Karsten Hopp 634b72
*** 716,717 ****
Karsten Hopp 634b72
--- 716,719 ----
Karsten Hopp 634b72
  {   /* Add new patch number below this line */
Karsten Hopp 634b72
+ /**/
Karsten Hopp 634b72
+     55,
Karsten Hopp 634b72
  /**/
Karsten Hopp 634b72
Karsten Hopp 634b72
-- 
Karsten Hopp 634b72
A special law prohibits unmarried women from parachuting on Sunday or she
Karsten Hopp 634b72
shall risk arrest, fine, and/or jailing.
Karsten Hopp 634b72
		[real standing law in Florida, United States of America]
Karsten Hopp 634b72
Karsten Hopp 634b72
 /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net   \\\
Karsten Hopp 634b72
///        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
Karsten Hopp 634b72
\\\        download, build and distribute -- http://www.A-A-P.org        ///
Karsten Hopp 634b72
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///