diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2002-12-06 15:09:00 -0200 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2002-12-06 15:09:00 -0200 |
commit | cc4a22ebe28c5d09566facde05840ddf42778eac (patch) | |
tree | 3c7b30728c9c819c04eeddb5558902236f3fecde | |
parent | acf62ddfbe1163f7cc1ab463842fb6a1b6aba8fe (diff) | |
download | lua-cc4a22ebe28c5d09566facde05840ddf42778eac.tar.gz lua-cc4a22ebe28c5d09566facde05840ddf42778eac.tar.bz2 lua-cc4a22ebe28c5d09566facde05840ddf42778eac.zip |
bug: scope of generic for variables is not sound
-rw-r--r-- | bugs | 5 | ||||
-rw-r--r-- | lparser.c | 52 | ||||
-rw-r--r-- | lvm.c | 25 |
3 files changed, 48 insertions, 34 deletions
@@ -298,3 +298,8 @@ Fri Aug 30 13:49:14 EST 2002 | |||
298 | >> userdata may not be cleared properly | 298 | >> userdata may not be cleared properly |
299 | (by Roberto; since 5.0a) | 299 | (by Roberto; since 5.0a) |
300 | 300 | ||
301 | ** lparser.c | ||
302 | Fri Dec 6 17:06:40 UTC 2002 | ||
303 | >> scope of generic for variables is not sound | ||
304 | (by Gavin Wraith; since 5.0a) | ||
305 | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lparser.c,v 1.199 2002/11/22 16:42:53 roberto Exp roberto $ | 2 | ** $Id: lparser.c,v 1.200 2002/12/04 17:38:31 roberto Exp roberto $ |
3 | ** Lua Parser | 3 | ** Lua Parser |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -303,8 +303,8 @@ static void pushclosure (LexState *ls, FuncState *func, expdesc *v) { | |||
303 | f->p[fs->np++] = func->f; | 303 | f->p[fs->np++] = func->f; |
304 | init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np-1)); | 304 | init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np-1)); |
305 | for (i=0; i<func->f->nupvalues; i++) { | 305 | for (i=0; i<func->f->nupvalues; i++) { |
306 | luaK_exp2nextreg(fs, &func->upvalues[i]); | 306 | OpCode o = (func->upvalues[i].k == VLOCAL) ? OP_MOVE : OP_GETUPVAL; |
307 | fs->freereg--; /* CLOSURE will use these values */ | 307 | luaK_codeABC(fs, o, 0, func->upvalues[i].info, 0); |
308 | } | 308 | } |
309 | } | 309 | } |
310 | 310 | ||
@@ -1014,10 +1014,27 @@ static int exp1 (LexState *ls) { | |||
1014 | } | 1014 | } |
1015 | 1015 | ||
1016 | 1016 | ||
1017 | static void forbody (LexState *ls, int base, int line, int nvars, int isnum) { | ||
1018 | BlockCnt bl; | ||
1019 | FuncState *fs = ls->fs; | ||
1020 | int prep, endfor; | ||
1021 | adjustlocalvars(ls, nvars); /* scope for all variables */ | ||
1022 | check(ls, TK_DO); | ||
1023 | enterblock(fs, &bl, 1); /* loop block */ | ||
1024 | prep = luaK_getlabel(fs); | ||
1025 | block(ls); | ||
1026 | luaK_patchtohere(fs, prep-1); | ||
1027 | endfor = (isnum) ? luaK_codeAsBx(fs, OP_FORLOOP, base, NO_JUMP) : | ||
1028 | luaK_codeABC(fs, OP_TFORLOOP, base, 0, nvars - 3); | ||
1029 | luaK_fixline(fs, line); /* pretend that `OP_FOR' starts the loop */ | ||
1030 | luaK_patchlist(fs, (isnum) ? endfor : luaK_jump(fs), prep); | ||
1031 | leaveblock(fs); | ||
1032 | } | ||
1033 | |||
1034 | |||
1017 | static void fornum (LexState *ls, TString *varname, int line) { | 1035 | static void fornum (LexState *ls, TString *varname, int line) { |
1018 | /* fornum -> NAME = exp1,exp1[,exp1] DO body */ | 1036 | /* fornum -> NAME = exp1,exp1[,exp1] DO body */ |
1019 | FuncState *fs = ls->fs; | 1037 | FuncState *fs = ls->fs; |
1020 | int prep, endfor; | ||
1021 | int base = fs->freereg; | 1038 | int base = fs->freereg; |
1022 | new_localvar(ls, varname, 0); | 1039 | new_localvar(ls, varname, 0); |
1023 | new_localvarstr(ls, "(for limit)", 1); | 1040 | new_localvarstr(ls, "(for limit)", 1); |
@@ -1032,16 +1049,9 @@ static void fornum (LexState *ls, TString *varname, int line) { | |||
1032 | luaK_codeABx(fs, OP_LOADK, fs->freereg, luaK_numberK(fs, 1)); | 1049 | luaK_codeABx(fs, OP_LOADK, fs->freereg, luaK_numberK(fs, 1)); |
1033 | luaK_reserveregs(fs, 1); | 1050 | luaK_reserveregs(fs, 1); |
1034 | } | 1051 | } |
1035 | adjustlocalvars(ls, 3); /* scope for control variables */ | ||
1036 | luaK_codeABC(fs, OP_SUB, fs->freereg - 3, fs->freereg - 3, fs->freereg - 1); | 1052 | luaK_codeABC(fs, OP_SUB, fs->freereg - 3, fs->freereg - 3, fs->freereg - 1); |
1037 | luaK_jump(fs); | 1053 | luaK_jump(fs); |
1038 | prep = luaK_getlabel(fs); | 1054 | forbody(ls, base, line, 3, 1); |
1039 | check(ls, TK_DO); | ||
1040 | block(ls); | ||
1041 | luaK_patchtohere(fs, prep-1); | ||
1042 | endfor = luaK_codeAsBx(fs, OP_FORLOOP, base, NO_JUMP); | ||
1043 | luaK_fixline(fs, line); /* pretend that `OP_FOR' starts the loop */ | ||
1044 | luaK_patchlist(fs, endfor, prep); | ||
1045 | } | 1055 | } |
1046 | 1056 | ||
1047 | 1057 | ||
@@ -1049,9 +1059,8 @@ static void forlist (LexState *ls, TString *indexname) { | |||
1049 | /* forlist -> NAME {,NAME} IN explist1 DO body */ | 1059 | /* forlist -> NAME {,NAME} IN explist1 DO body */ |
1050 | FuncState *fs = ls->fs; | 1060 | FuncState *fs = ls->fs; |
1051 | expdesc e; | 1061 | expdesc e; |
1052 | int line; | ||
1053 | int nvars = 0; | 1062 | int nvars = 0; |
1054 | int prep; | 1063 | int line; |
1055 | int base = fs->freereg; | 1064 | int base = fs->freereg; |
1056 | new_localvarstr(ls, "(for generator)", nvars++); | 1065 | new_localvarstr(ls, "(for generator)", nvars++); |
1057 | new_localvarstr(ls, "(for state)", nvars++); | 1066 | new_localvarstr(ls, "(for state)", nvars++); |
@@ -1060,18 +1069,9 @@ static void forlist (LexState *ls, TString *indexname) { | |||
1060 | new_localvar(ls, str_checkname(ls), nvars++); | 1069 | new_localvar(ls, str_checkname(ls), nvars++); |
1061 | check(ls, TK_IN); | 1070 | check(ls, TK_IN); |
1062 | line = ls->linenumber; | 1071 | line = ls->linenumber; |
1063 | adjust_assign(ls, 3, explist1(ls, &e), &e); | 1072 | adjust_assign(ls, nvars, explist1(ls, &e), &e); |
1064 | luaK_reserveregs(fs, nvars - 3); /* registers for other variables */ | ||
1065 | luaK_codeAsBx(fs, OP_TFORPREP, base, NO_JUMP); | 1073 | luaK_codeAsBx(fs, OP_TFORPREP, base, NO_JUMP); |
1066 | adjustlocalvars(ls, nvars); /* scope for all variables */ | 1074 | forbody(ls, base, line, nvars, 0); |
1067 | check(ls, TK_DO); | ||
1068 | prep = luaK_getlabel(fs); | ||
1069 | block(ls); | ||
1070 | luaK_patchtohere(fs, prep-1); | ||
1071 | removevars(fs->ls, fs->nactvar - nvars); /* deactivate locals for next op. */ | ||
1072 | luaK_codeABC(fs, OP_TFORLOOP, base, 0, nvars - 3); | ||
1073 | luaK_fixline(fs, line); /* pretend that `OP_FOR' starts the loop */ | ||
1074 | luaK_patchlist(fs, luaK_jump(fs), prep); | ||
1075 | } | 1075 | } |
1076 | 1076 | ||
1077 | 1077 | ||
@@ -1080,7 +1080,7 @@ static void forstat (LexState *ls, int line) { | |||
1080 | FuncState *fs = ls->fs; | 1080 | FuncState *fs = ls->fs; |
1081 | TString *varname; | 1081 | TString *varname; |
1082 | BlockCnt bl; | 1082 | BlockCnt bl; |
1083 | enterblock(fs, &bl, 1); | 1083 | enterblock(fs, &bl, 0); /* block to control variable scope */ |
1084 | next(ls); /* skip `for' */ | 1084 | next(ls); /* skip `for' */ |
1085 | varname = str_checkname(ls); /* first variable name */ | 1085 | varname = str_checkname(ls); /* first variable name */ |
1086 | switch (ls->t.token) { | 1086 | switch (ls->t.token) { |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lvm.c,v 1.270 2002/11/25 17:47:13 roberto Exp roberto $ | 2 | ** $Id: lvm.c,v 1.271 2002/12/04 17:38:31 roberto Exp roberto $ |
3 | ** Lua virtual machine | 3 | ** Lua virtual machine |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -671,14 +671,23 @@ StkId luaV_execute (lua_State *L) { | |||
671 | break; | 671 | break; |
672 | } | 672 | } |
673 | case OP_TFORLOOP: { | 673 | case OP_TFORLOOP: { |
674 | setobjs2s(ra+4, ra+2); | 674 | int nvar = GETARG_C(i) + 1; |
675 | setobjs2s(ra+3, ra+1); | 675 | StkId cb = ra + nvar + 2; /* call base */ |
676 | setobjs2s(ra+2, ra); | 676 | setobjs2s(cb, ra); |
677 | L->top = ra+5; | 677 | setobjs2s(cb+1, ra+1); |
678 | luaD_call(L, ra+2, GETARG_C(i) + 1); | 678 | setobjs2s(cb+2, ra+2); |
679 | L->top = cb+3; /* func. + 2 args (state and index) */ | ||
680 | luaD_call(L, cb, nvar); | ||
679 | L->top = L->ci->top; | 681 | L->top = L->ci->top; |
680 | if (ttisnil(XRA(i)+2)) pc++; /* skip jump (break loop) */ | 682 | ra = XRA(i); /* call may change stack */ |
681 | else dojump(pc, GETARG_sBx(*pc) + 1); /* else jump back */ | 683 | cb = ra + nvar + 2; |
684 | if (ttisnil(cb)) /* break loop? */ | ||
685 | pc++; /* skip jump (break loop) */ | ||
686 | else { | ||
687 | while (nvar--) /* move results to proper positions */ | ||
688 | setobjs2s(ra+2+nvar, cb+nvar); | ||
689 | dojump(pc, GETARG_sBx(*pc) + 1); /* jump back */ | ||
690 | } | ||
682 | break; | 691 | break; |
683 | } | 692 | } |
684 | case OP_TFORPREP: { /* for compatibility only */ | 693 | case OP_TFORPREP: { /* for compatibility only */ |