summaryrefslogtreecommitdiffstats
path: root/src/eval.c
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2010-11-10 20:41:57 +0100
committerBram Moolenaar <Bram@vim.org>2010-11-10 20:41:57 +0100
commit67b3f99eb0f4b2014316c7f0152cefc4d6cfc765 (patch)
treed84b58b0efc20ef43827d37c9fd55728f53fc84a /src/eval.c
parenta3e7b1f42b3d91de6f3e5f01d8067cf0079be56c (diff)
updated for version 7.3.055v7.3.055
Problem: Recursively nested lists and dictionaries cause a near-endless loop when comparing them with a copy. (ZyX) Solution: Limit recursiveness in a way that non-recursive structures can still be nested very deep. Files: src/eval.c, src/testdir/test55.in, src/testdir/test55.ok
Diffstat (limited to 'src/eval.c')
-rw-r--r--src/eval.c63
1 files changed, 40 insertions, 23 deletions
diff --git a/src/eval.c b/src/eval.c
index d7cee74350..7c3abf1f57 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -434,9 +434,9 @@ static listitem_T *listitem_alloc __ARGS((void));
static void listitem_free __ARGS((listitem_T *item));
static void listitem_remove __ARGS((list_T *l, listitem_T *item));
static long list_len __ARGS((list_T *l));
-static int list_equal __ARGS((list_T *l1, list_T *l2, int ic));
-static int dict_equal __ARGS((dict_T *d1, dict_T *d2, int ic));
-static int tv_equal __ARGS((typval_T *tv1, typval_T *tv2, int ic));
+static int list_equal __ARGS((list_T *l1, list_T *l2, int ic, int recursive));
+static int dict_equal __ARGS((dict_T *d1, dict_T *d2, int ic, int recursive));
+static int tv_equal __ARGS((typval_T *tv1, typval_T *tv2, int ic, int recursive));
static listitem_T *list_find __ARGS((list_T *l, long n));
static long list_find_nr __ARGS((list_T *l, long idx, int *errorp));
static long list_idx_of_item __ARGS((list_T *l, listitem_T *item));
@@ -4350,7 +4350,8 @@ eval4(arg, rettv, evaluate)
else
{
/* Compare two Lists for being equal or unequal. */
- n1 = list_equal(rettv->vval.v_list, var2.vval.v_list, ic);
+ n1 = list_equal(rettv->vval.v_list, var2.vval.v_list,
+ ic, FALSE);
if (type == TYPE_NEQUAL)
n1 = !n1;
}
@@ -4379,7 +4380,8 @@ eval4(arg, rettv, evaluate)
else
{
/* Compare two Dictionaries for being equal or unequal. */
- n1 = dict_equal(rettv->vval.v_dict, var2.vval.v_dict, ic);
+ n1 = dict_equal(rettv->vval.v_dict, var2.vval.v_dict,
+ ic, FALSE);
if (type == TYPE_NEQUAL)
n1 = !n1;
}
@@ -5914,10 +5916,11 @@ list_len(l)
* Return TRUE when two lists have exactly the same values.
*/
static int
-list_equal(l1, l2, ic)
+list_equal(l1, l2, ic, recursive)
list_T *l1;
list_T *l2;
int ic; /* ignore case for strings */
+ int recursive; /* TRUE when used recursively */
{
listitem_T *item1, *item2;
@@ -5931,7 +5934,7 @@ list_equal(l1, l2, ic)
for (item1 = l1->lv_first, item2 = l2->lv_first;
item1 != NULL && item2 != NULL;
item1 = item1->li_next, item2 = item2->li_next)
- if (!tv_equal(&item1->li_tv, &item2->li_tv, ic))
+ if (!tv_equal(&item1->li_tv, &item2->li_tv, ic, recursive))
return FALSE;
return item1 == NULL && item2 == NULL;
}
@@ -5953,10 +5956,11 @@ dict_lookup(hi)
* Return TRUE when two dictionaries have exactly the same key/values.
*/
static int
-dict_equal(d1, d2, ic)
+dict_equal(d1, d2, ic, recursive)
dict_T *d1;
dict_T *d2;
int ic; /* ignore case for strings */
+ int recursive; /* TRUE when used recursively */
{
hashitem_T *hi;
dictitem_T *item2;
@@ -5977,7 +5981,7 @@ dict_equal(d1, d2, ic)
item2 = dict_find(d2, hi->hi_key, -1);
if (item2 == NULL)
return FALSE;
- if (!tv_equal(&HI2DI(hi)->di_tv, &item2->di_tv, ic))
+ if (!tv_equal(&HI2DI(hi)->di_tv, &item2->di_tv, ic, recursive))
return FALSE;
--todo;
}
@@ -5985,41 +5989,54 @@ dict_equal(d1, d2, ic)
return TRUE;
}
+static int tv_equal_recurse_limit;
+
/*
* Return TRUE if "tv1" and "tv2" have the same value.
* Compares the items just like "==" would compare them, but strings and
* numbers are different. Floats and numbers are also different.
*/
static int
-tv_equal(tv1, tv2, ic)
+tv_equal(tv1, tv2, ic, recursive)
typval_T *tv1;
typval_T *tv2;
- int ic; /* ignore case */
+ int ic; /* ignore case */
+ int recursive; /* TRUE when used recursively */
{
char_u buf1[NUMBUFLEN], buf2[NUMBUFLEN];
char_u *s1, *s2;
- static int recursive = 0; /* cach recursive loops */
+ static int recursive_cnt = 0; /* catch recursive loops */
int r;
if (tv1->v_type != tv2->v_type)
return FALSE;
+
/* Catch lists and dicts that have an endless loop by limiting
- * recursiveness to 1000. We guess they are equal then. */
- if (recursive >= 1000)
+ * recursiveness to a limit. We guess they are equal then.
+ * A fixed limit has the problem of still taking an awful long time.
+ * Reduce the limit every time running into it. That should work fine for
+ * deeply linked structures that are not recursively linked and catch
+ * recursiveness quickly. */
+ if (!recursive)
+ tv_equal_recurse_limit = 1000;
+ if (recursive_cnt >= tv_equal_recurse_limit)
+ {
+ --tv_equal_recurse_limit;
return TRUE;
+ }
switch (tv1->v_type)
{
case VAR_LIST:
- ++recursive;
- r = list_equal(tv1->vval.v_list, tv2->vval.v_list, ic);
- --recursive;
+ ++recursive_cnt;
+ r = list_equal(tv1->vval.v_list, tv2->vval.v_list, ic, TRUE);
+ --recursive_cnt;
return r;
case VAR_DICT:
- ++recursive;
- r = dict_equal(tv1->vval.v_dict, tv2->vval.v_dict, ic);
- --recursive;
+ ++recursive_cnt;
+ r = dict_equal(tv1->vval.v_dict, tv2->vval.v_dict, ic, TRUE);
+ --recursive_cnt;
return r;
case VAR_FUNC:
@@ -9391,7 +9408,7 @@ f_count(argvars, rettv)
}
for ( ; li != NULL; li = li->li_next)
- if (tv_equal(&li->li_tv, &argvars[1], ic))
+ if (tv_equal(&li->li_tv, &argvars[1], ic, FALSE))
++n;
}
}
@@ -9418,7 +9435,7 @@ f_count(argvars, rettv)
if (!HASHITEM_EMPTY(hi))
{
--todo;
- if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic))
+ if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic, FALSE))
++n;
}
}
@@ -12574,7 +12591,7 @@ f_index(argvars, rettv)
}
for ( ; item != NULL; item = item->li_next, ++idx)
- if (tv_equal(&item->li_tv, &argvars[1], ic))
+ if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
{
rettv->vval.v_number = idx;
break;