[git commit master] awk: fix the case where nested "for" loops with the same variable misbehave

Denys Vlasenko vda.linux at googlemail.com
Wed Mar 10 18:20:32 UTC 2010


commit: http://git.busybox.net/busybox/commit/?id=3cb60c39737208ca073842f4f0386d5e5c278705
branch: http://git.busybox.net/busybox/commit/?id=refs/heads/master

Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 editors/awk.c       |   30 ++++++++++++++++++++----------
 testsuite/awk.tests |   38 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 58 insertions(+), 10 deletions(-)

diff --git a/editors/awk.c b/editors/awk.c
index b9bc01f..5cc4adc 100644
--- a/editors/awk.c
+++ b/editors/awk.c
@@ -912,8 +912,10 @@ static void nvfree(var *v)
 			free(p->x.array->items);
 			free(p->x.array);
 		}
-		if (p->type & VF_WALK)
+		if (p->type & VF_WALK) {
+			//bb_error_msg("free(walker@%p:%p) #1", &p->x.walker, p->x.walker);
 			free(p->x.walker);
+		}
 
 		clrvar(p);
 	}
@@ -1724,18 +1726,20 @@ static void hashwalk_init(var *v, xhash *array)
 	char **w;
 	hash_item *hi;
 	unsigned i;
-
-	if (v->type & VF_WALK)
-		free(v->x.walker);
+	char **prev_walker = (v->type & VF_WALK) ? v->x.walker : NULL;
 
 	v->type |= VF_WALK;
-	w = v->x.walker = xzalloc(2 + 2*sizeof(char *) + array->glen);
-	w[0] = w[1] = (char *)(w + 2);
+
+	/* walker structure is: "[ptr2end][ptr2start][prev]<word1>NUL<word2>NUL" */
+	w = v->x.walker = xzalloc(2 + 3*sizeof(char *) + array->glen);
+	//bb_error_msg("walker@%p=%p", &v->x.walker, v->x.walker);
+	w[0] = w[1] = (char *)(w + 3);
+	w[2] = (char *)prev_walker;
 	for (i = 0; i < array->csize; i++) {
 		hi = array->items[i];
 		while (hi) {
-			strcpy(*w, hi->name);
-			nextword(w);
+			strcpy(w[0], hi->name);
+			nextword(&w[0]);
 			hi = hi->next;
 		}
 	}
@@ -1746,10 +1750,16 @@ static int hashwalk_next(var *v)
 	char **w;
 
 	w = v->x.walker;
-	if (w[1] == w[0])
+	if (w[1] == w[0]) {
+		char **prev_walker = (char**)w[2];
+
+		//bb_error_msg("free(walker@%p:%p) #3, restoring to %p", &v->x.walker, v->x.walker, prev_walker);
+		free(v->x.walker);
+		v->x.walker = prev_walker;
 		return FALSE;
+	}
 
-	setvar_s(v, nextword(w+1));
+	setvar_s(v, nextword(&w[1]));
 	return TRUE;
 }
 
diff --git a/testsuite/awk.tests b/testsuite/awk.tests
index 03d4649..78f9f0b 100755
--- a/testsuite/awk.tests
+++ b/testsuite/awk.tests
@@ -67,4 +67,42 @@ testing "awk string cast (bug 725)" \
 testing "awk handles whitespace before array subscript" \
 	"awk 'BEGIN { arr [3] = 1; print arr [3] }'" "1\n" "" ""
 
+prg='
+BEGIN {
+  v["q"]=1
+  v["w"]=1
+  v["e"]=1
+  for (l in v) {
+    print "outer1", l;
+    for (l in v) {
+      print " inner", l;
+    }
+    print "outer2", l;
+  }
+  print "end", l;
+  l="a"
+  exit;
+}'
+testing "awk nested loops with the same variable" \
+	"awk '$prg'" \
+	"\
+outer1 e
+ inner e
+ inner q
+ inner w
+outer2 w
+outer1 q
+ inner e
+ inner q
+ inner w
+outer2 w
+outer1 w
+ inner e
+ inner q
+ inner w
+outer2 w
+end w
+" \
+	"" ""
+
 exit $FAILCOUNT
-- 
1.6.3.3



More information about the busybox-cvs mailing list