awk: fix the case where nested "for" loops with the same variable misbehave
No binary (build failed)
—
(log yok)
| @@ -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; | |
| } | |
| @@ -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 | |