diff lwlib/lw_expr.c @ 431:d7d7e4dca3e7

Eliminated infinite loop on recursive symbol resolution with a Q&D hack: limit the depth that lw_expr_simplify can be called to globally. Not thread friendly.
author lost@l-w.ca
date Sun, 24 Oct 2010 20:05:15 -0600
parents 652eee8f0c82
children 22bbb716dea6
line wrap: on
line diff
--- a/lwlib/lw_expr.c	Sun Oct 24 19:06:00 2010 -0600
+++ b/lwlib/lw_expr.c	Sun Oct 24 20:05:15 2010 -0600
@@ -35,6 +35,10 @@
 static lw_expr_fn2_t *evaluate_var = NULL;
 static lw_expr_fn3_t *parse_term = NULL;
 
+/* Q&D to break out of infinite recursion */
+static int level = 0;
+static int bailing = 0;
+
 int lw_expr_istype(lw_expr_t e, int t)
 {
 	if (e -> type == t)
@@ -337,6 +341,9 @@
 	if (E1 == E2)
 		return 1;
 
+	if (!E1 || !E2)
+		return 0;
+
 	if (!(E1 -> type == E2 -> type && E1 -> value == E2 -> value))
 		return 0;
 
@@ -453,6 +460,8 @@
 		
 		// not a times - have to assume it's the operand list
 		// with a "1 *" in front if it
+		if (!e1 -> operands -> next)
+			return 0;
 		if (e1 -> operands -> next -> next)
 			return 0;
 		if (!lw_expr_compare(e1 -> operands -> next -> p, e2))
@@ -477,7 +486,29 @@
 	return 1;
 }
 
-void lw_expr_simplify(lw_expr_t E, void *priv);
+int lw_expr_contains(lw_expr_t E, lw_expr_t E1)
+{
+	struct lw_expr_opers *o;
+	
+	// NULL expr contains nothing :)
+	if (!E)
+		return 0;
+	
+	if (E1 -> type != lw_expr_type_var && E1 -> type != lw_expr_type_special)
+		return 0;
+	
+	if (lw_expr_compare(E, E1))
+		return 1;
+	
+	for (o = E -> operands; o; o = o -> next)
+	{
+		if (lw_expr_contains(o -> p, E1))
+			return 1;
+	}
+	return 0;
+}
+
+void lw_expr_simplify_l(lw_expr_t E, void *priv);
 
 void lw_expr_simplify_go(lw_expr_t E, void *priv)
 {
@@ -518,6 +549,8 @@
 		lw_expr_t te;
 		
 		te = evaluate_special(E -> value, E -> value2, priv);
+		if (lw_expr_contains(te, E))
+			lw_expr_destroy(te);
 		if (te)
 		{
 			for (o = E -> operands; o; o = o -> next)
@@ -544,7 +577,9 @@
 		lw_expr_t te;
 		
 		te = evaluate_var(E -> value2, priv);
-		if (te)
+		if (lw_expr_contains(te, E))
+			lw_expr_destroy(te);
+		else if (te)
 		{
 			for (o = E -> operands; o; o = o -> next)
 				lw_expr_destroy(o -> p);
@@ -631,7 +666,7 @@
 	
 	// simplify operands
 	for (o = E -> operands; o; o = o -> next)
-		lw_expr_simplify(o -> p, priv);
+		lw_expr_simplify_l(o -> p, priv);
 
 	for (o = E -> operands; o; o = o -> next)
 	{
@@ -993,10 +1028,21 @@
 	}
 }
 
-void lw_expr_simplify(lw_expr_t E, void *priv)
+void lw_expr_simplify_l(lw_expr_t E, void *priv)
 {
 	lw_expr_t te;
 	int c;
+	
+	(level)++;
+	// bail out if the level gets too deep
+	if (level >= 500 || bailing)
+	{
+		bailing = 1;
+		level--;
+		if (level == 0)
+			bailing = 0;
+		return;
+	}
 	do
 	{
 		te = lw_expr_copy(E);
@@ -1007,8 +1053,13 @@
 		lw_expr_destroy(te);
 	}
 	while (c);
+	(level)--;
 }
 
+void lw_expr_simplify(lw_expr_t E, void *priv)
+{
+	lw_expr_simplify_l(E, priv);
+}
 
 /*