diff options
author | Denys Vlasenko | 2010-03-10 19:20:32 +0100 |
---|---|---|
committer | Denys Vlasenko | 2010-03-10 19:20:32 +0100 |
commit | 3cb60c39737208ca073842f4f0386d5e5c278705 (patch) | |
tree | 7e96890a5016885d75dea187edd1c63cbbf05f6a | |
parent | eae697fb93362dd51365fdd5283128cb339b91c2 (diff) | |
download | busybox-3cb60c39737208ca073842f4f0386d5e5c278705.zip busybox-3cb60c39737208ca073842f4f0386d5e5c278705.tar.gz |
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.c | 30 | ||||
-rwxr-xr-x | 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 |