diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2020-06-01 15:07:58 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2020-06-01 15:07:58 -0300 |
commit | 63295f1f7fa052fabcb4d69d49203cf33a7deef0 (patch) | |
tree | 05ba23f84fc76bd9a6b44883e7527ca1afcd274e /lparser.c | |
parent | 50523b107d5bcc8069b1aec4b5b11b3fcc87da8d (diff) | |
download | lua-63295f1f7fa052fabcb4d69d49203cf33a7deef0.tar.gz lua-63295f1f7fa052fabcb4d69d49203cf33a7deef0.tar.bz2 lua-63295f1f7fa052fabcb4d69d49203cf33a7deef0.zip |
Fixed two bugs in to-be-closed variables x constants
The parser were mixing compiler indices of variables with stack indices,
so that when a to-be-closed variable was used inside the scope of
compile-time constants (which may be optimized away), it might be closed
in the wrong place. (See new tests for examples.)
Besides fixing the bugs, this commit also changed comments and variable
names to avoid that kind of confusion and added tests.
Diffstat (limited to 'lparser.c')
-rw-r--r-- | lparser.c | 64 |
1 files changed, 36 insertions, 28 deletions
@@ -212,27 +212,28 @@ static int new_localvar (LexState *ls, TString *name) { | |||
212 | 212 | ||
213 | 213 | ||
214 | /* | 214 | /* |
215 | ** Return the "variable description" (Vardesc) of a given | 215 | ** Return the "variable description" (Vardesc) of a given variable. |
216 | ** variable | 216 | ** (Unless noted otherwise, all variables are referred to by their |
217 | ** compiler indices.) | ||
217 | */ | 218 | */ |
218 | static Vardesc *getlocalvardesc (FuncState *fs, int i) { | 219 | static Vardesc *getlocalvardesc (FuncState *fs, int vidx) { |
219 | return &fs->ls->dyd->actvar.arr[fs->firstlocal + i]; | 220 | return &fs->ls->dyd->actvar.arr[fs->firstlocal + vidx]; |
220 | } | 221 | } |
221 | 222 | ||
222 | 223 | ||
223 | /* | 224 | /* |
224 | ** Convert 'nvar' (number of active variables at some point) to | 225 | ** Convert 'nvar', a compiler index level, to it corresponding |
225 | ** number of variables in the stack at that point. | 226 | ** stack index level. For that, search for the highest variable |
227 | ** below that level that is in the stack and uses its stack | ||
228 | ** index ('sidx'). | ||
226 | */ | 229 | */ |
227 | static int stacklevel (FuncState *fs, int nvar) { | 230 | static int stacklevel (FuncState *fs, int nvar) { |
228 | while (nvar > 0) { | 231 | while (nvar-- > 0) { |
229 | Vardesc *vd = getlocalvardesc(fs, nvar - 1); | 232 | Vardesc *vd = getlocalvardesc(fs, nvar); /* get variable */ |
230 | if (vd->vd.kind != RDKCTC) /* is in the stack? */ | 233 | if (vd->vd.kind != RDKCTC) /* is in the stack? */ |
231 | return vd->vd.sidx + 1; | 234 | return vd->vd.sidx + 1; |
232 | else | ||
233 | nvar--; /* try previous variable */ | ||
234 | } | 235 | } |
235 | return 0; /* no variables */ | 236 | return 0; /* no variables in the stack */ |
236 | } | 237 | } |
237 | 238 | ||
238 | 239 | ||
@@ -245,10 +246,10 @@ int luaY_nvarstack (FuncState *fs) { | |||
245 | 246 | ||
246 | 247 | ||
247 | /* | 248 | /* |
248 | ** Get the debug-information entry for current variable 'i'. | 249 | ** Get the debug-information entry for current variable 'vidx'. |
249 | */ | 250 | */ |
250 | static LocVar *localdebuginfo (FuncState *fs, int i) { | 251 | static LocVar *localdebuginfo (FuncState *fs, int vidx) { |
251 | Vardesc *vd = getlocalvardesc(fs, i); | 252 | Vardesc *vd = getlocalvardesc(fs, vidx); |
252 | if (vd->vd.kind == RDKCTC) | 253 | if (vd->vd.kind == RDKCTC) |
253 | return NULL; /* no debug info. for constants */ | 254 | return NULL; /* no debug info. for constants */ |
254 | else { | 255 | else { |
@@ -259,14 +260,20 @@ static LocVar *localdebuginfo (FuncState *fs, int i) { | |||
259 | } | 260 | } |
260 | 261 | ||
261 | 262 | ||
262 | static void init_var (FuncState *fs, expdesc *e, int i) { | 263 | /* |
264 | ** Create an expression representing variable 'vidx' | ||
265 | */ | ||
266 | static void init_var (FuncState *fs, expdesc *e, int vidx) { | ||
263 | e->f = e->t = NO_JUMP; | 267 | e->f = e->t = NO_JUMP; |
264 | e->k = VLOCAL; | 268 | e->k = VLOCAL; |
265 | e->u.var.vidx = i; | 269 | e->u.var.vidx = vidx; |
266 | e->u.var.sidx = getlocalvardesc(fs, i)->vd.sidx; | 270 | e->u.var.sidx = getlocalvardesc(fs, vidx)->vd.sidx; |
267 | } | 271 | } |
268 | 272 | ||
269 | 273 | ||
274 | /* | ||
275 | ** Raises an error if variable described by 'e' is read only | ||
276 | */ | ||
270 | static void check_readonly (LexState *ls, expdesc *e) { | 277 | static void check_readonly (LexState *ls, expdesc *e) { |
271 | FuncState *fs = ls->fs; | 278 | FuncState *fs = ls->fs; |
272 | TString *varname = NULL; /* to be set if variable is const */ | 279 | TString *varname = NULL; /* to be set if variable is const */ |
@@ -306,8 +313,8 @@ static void adjustlocalvars (LexState *ls, int nvars) { | |||
306 | int stklevel = luaY_nvarstack(fs); | 313 | int stklevel = luaY_nvarstack(fs); |
307 | int i; | 314 | int i; |
308 | for (i = 0; i < nvars; i++) { | 315 | for (i = 0; i < nvars; i++) { |
309 | int varidx = fs->nactvar++; | 316 | int vidx = fs->nactvar++; |
310 | Vardesc *var = getlocalvardesc(fs, varidx); | 317 | Vardesc *var = getlocalvardesc(fs, vidx); |
311 | var->vd.sidx = stklevel++; | 318 | var->vd.sidx = stklevel++; |
312 | var->vd.pidx = registerlocalvar(ls, fs, var->vd.name); | 319 | var->vd.pidx = registerlocalvar(ls, fs, var->vd.name); |
313 | } | 320 | } |
@@ -377,7 +384,8 @@ static int newupvalue (FuncState *fs, TString *name, expdesc *v) { | |||
377 | 384 | ||
378 | /* | 385 | /* |
379 | ** Look for an active local variable with the name 'n' in the | 386 | ** Look for an active local variable with the name 'n' in the |
380 | ** function 'fs'. | 387 | ** function 'fs'. If found, initialize 'var' with it and return |
388 | ** its expression kind; otherwise return -1. | ||
381 | */ | 389 | */ |
382 | static int searchvar (FuncState *fs, TString *n, expdesc *var) { | 390 | static int searchvar (FuncState *fs, TString *n, expdesc *var) { |
383 | int i; | 391 | int i; |
@@ -1592,7 +1600,7 @@ static void forlist (LexState *ls, TString *indexname) { | |||
1592 | line = ls->linenumber; | 1600 | line = ls->linenumber; |
1593 | adjust_assign(ls, 4, explist(ls, &e), &e); | 1601 | adjust_assign(ls, 4, explist(ls, &e), &e); |
1594 | adjustlocalvars(ls, 4); /* control variables */ | 1602 | adjustlocalvars(ls, 4); /* control variables */ |
1595 | markupval(fs, luaY_nvarstack(fs)); /* state may create an upvalue */ | 1603 | markupval(fs, fs->nactvar); /* last control var. must be closed */ |
1596 | luaK_checkstack(fs, 3); /* extra space to call generator */ | 1604 | luaK_checkstack(fs, 3); /* extra space to call generator */ |
1597 | forbody(ls, base, line, nvars - 4, 1); | 1605 | forbody(ls, base, line, nvars - 4, 1); |
1598 | } | 1606 | } |
@@ -1730,7 +1738,7 @@ static int getlocalattribute (LexState *ls) { | |||
1730 | luaK_semerror(ls, | 1738 | luaK_semerror(ls, |
1731 | luaO_pushfstring(ls->L, "unknown attribute '%s'", attr)); | 1739 | luaO_pushfstring(ls->L, "unknown attribute '%s'", attr)); |
1732 | } | 1740 | } |
1733 | return VDKREG; | 1741 | return VDKREG; /* regular variable */ |
1734 | } | 1742 | } |
1735 | 1743 | ||
1736 | 1744 | ||
@@ -1739,7 +1747,7 @@ static void checktoclose (LexState *ls, int level) { | |||
1739 | FuncState *fs = ls->fs; | 1747 | FuncState *fs = ls->fs; |
1740 | markupval(fs, level + 1); | 1748 | markupval(fs, level + 1); |
1741 | fs->bl->insidetbc = 1; /* in the scope of a to-be-closed variable */ | 1749 | fs->bl->insidetbc = 1; /* in the scope of a to-be-closed variable */ |
1742 | luaK_codeABC(fs, OP_TBC, level, 0, 0); | 1750 | luaK_codeABC(fs, OP_TBC, stacklevel(fs, level), 0, 0); |
1743 | } | 1751 | } |
1744 | } | 1752 | } |
1745 | 1753 | ||
@@ -1749,18 +1757,18 @@ static void localstat (LexState *ls) { | |||
1749 | FuncState *fs = ls->fs; | 1757 | FuncState *fs = ls->fs; |
1750 | int toclose = -1; /* index of to-be-closed variable (if any) */ | 1758 | int toclose = -1; /* index of to-be-closed variable (if any) */ |
1751 | Vardesc *var; /* last variable */ | 1759 | Vardesc *var; /* last variable */ |
1752 | int ivar, kind; /* index and kind of last variable */ | 1760 | int vidx, kind; /* index and kind of last variable */ |
1753 | int nvars = 0; | 1761 | int nvars = 0; |
1754 | int nexps; | 1762 | int nexps; |
1755 | expdesc e; | 1763 | expdesc e; |
1756 | do { | 1764 | do { |
1757 | ivar = new_localvar(ls, str_checkname(ls)); | 1765 | vidx = new_localvar(ls, str_checkname(ls)); |
1758 | kind = getlocalattribute(ls); | 1766 | kind = getlocalattribute(ls); |
1759 | getlocalvardesc(fs, ivar)->vd.kind = kind; | 1767 | getlocalvardesc(fs, vidx)->vd.kind = kind; |
1760 | if (kind == RDKTOCLOSE) { /* to-be-closed? */ | 1768 | if (kind == RDKTOCLOSE) { /* to-be-closed? */ |
1761 | if (toclose != -1) /* one already present? */ | 1769 | if (toclose != -1) /* one already present? */ |
1762 | luaK_semerror(ls, "multiple to-be-closed variables in local list"); | 1770 | luaK_semerror(ls, "multiple to-be-closed variables in local list"); |
1763 | toclose = luaY_nvarstack(fs) + nvars; | 1771 | toclose = fs->nactvar + nvars; |
1764 | } | 1772 | } |
1765 | nvars++; | 1773 | nvars++; |
1766 | } while (testnext(ls, ',')); | 1774 | } while (testnext(ls, ',')); |
@@ -1770,7 +1778,7 @@ static void localstat (LexState *ls) { | |||
1770 | e.k = VVOID; | 1778 | e.k = VVOID; |
1771 | nexps = 0; | 1779 | nexps = 0; |
1772 | } | 1780 | } |
1773 | var = getlocalvardesc(fs, ivar); /* get last variable */ | 1781 | var = getlocalvardesc(fs, vidx); /* get last variable */ |
1774 | if (nvars == nexps && /* no adjustments? */ | 1782 | if (nvars == nexps && /* no adjustments? */ |
1775 | var->vd.kind == RDKCONST && /* last variable is const? */ | 1783 | var->vd.kind == RDKCONST && /* last variable is const? */ |
1776 | luaK_exp2const(fs, &e, &var->k)) { /* compile-time constant? */ | 1784 | luaK_exp2const(fs, &e, &var->k)) { /* compile-time constant? */ |