summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2010-03-10 18:20:32 (GMT)
committer Denys Vlasenko <vda.linux@googlemail.com>2010-03-10 18:20:32 (GMT)
commit3cb60c39737208ca073842f4f0386d5e5c278705 (patch)
tree7e96890a5016885d75dea187edd1c63cbbf05f6a
parenteae697fb93362dd51365fdd5283128cb339b91c2 (diff)
downloadbusybox-3cb60c39737208ca073842f4f0386d5e5c278705.tar.gz
busybox-3cb60c39737208ca073842f4f0386d5e5c278705.tar.bz2
awk: fix the case where nested "for" loops with the same variable misbehave
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--editors/awk.c30
-rwxr-xr-xtestsuite/awk.tests38
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