Skip to content

Commit

Permalink
Fix possible infinite loop with nested switch expressions
Browse files Browse the repository at this point in the history
  • Loading branch information
Sainan committed Jun 28, 2024
1 parent 57548d2 commit 116304a
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 14 deletions.
23 changes: 9 additions & 14 deletions src/lparser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3194,9 +3194,8 @@ static void switchimpl (LexState *ls, int tk, void(*caselist)(LexState*,void*),
const auto nactvar = fs->nactvar;

std::vector<int>& first = ls->switchstates.top().first;
TString* const begin_switch = luaS_newliteral(ls->L, "pluto_begin_switch");
TString* default_case = nullptr;
int first_pc, default_pc;
int default_pc = -1;
int first_pc, goto_begin_pc;

if (gett(ls) == TK_CASE) {
luaX_next(ls); /* Skip 'case' */
Expand All @@ -3205,7 +3204,7 @@ static void switchimpl (LexState *ls, int tk, void(*caselist)(LexState*,void*),
caselist(ls, ud);
}
else {
newgotoentry(ls, begin_switch, ls->getLineNumber(), luaK_jump(fs), false); // goto begin_switch
goto_begin_pc = luaK_jump(fs);
}

std::vector<SwitchCase>& cases = ls->switchstates.top().cases;
Expand All @@ -3221,11 +3220,9 @@ static void switchimpl (LexState *ls, int tk, void(*caselist)(LexState*,void*),
if (gett(ls) == TK_DEFAULT) {
luaX_next(ls); /* Skip 'default' */
checknext(ls, tk);
if (default_case != nullptr)
if (default_pc != -1)
throwerr(ls, "switch statement already has a default case", "second default case", case_line);
default_case = luaS_newliteral(ls->L, "pluto_default_case");
default_pc = luaK_getlabel(fs);
createlabel(ls, default_case, ls->getLineNumber(), false, false);
}
else {
checknext(ls, TK_CASE);
Expand All @@ -3246,10 +3243,8 @@ static void switchimpl (LexState *ls, int tk, void(*caselist)(LexState*,void*),

/* if switch expression has no default case, generate one to guarantee nil in that case
otherwise, the value returned by the expression would be whatever was in the register before */
if (tk == TK_ARROW && default_case == nullptr) {
default_case = luaS_newliteral(ls->L, "pluto_default_case");
if (tk == TK_ARROW && default_pc == -1) {
default_pc = luaK_getlabel(fs);
createlabel(ls, default_case, ls->getLineNumber(), false, false);
const auto line = ls->getLineNumber();
const auto reg = reinterpret_cast<expdesc*>(ud)->u.reg;
expdesc cv;
Expand All @@ -3266,11 +3261,11 @@ static void switchimpl (LexState *ls, int tk, void(*caselist)(LexState*,void*),
luaK_patchtohere(fs, first.back());
}
else {
createlabel(ls, begin_switch, ls->getLineNumber(), false, false); // ::begin_switch::
luaK_patchtohere(fs, goto_begin_pc);
}

/* prune cases that lead to default case */
if (default_case) {
if (default_pc != -1) {
for (auto i = cases.begin(); i != cases.end(); ) {
if (i->pc == default_pc) {
i = cases.erase(i);
Expand All @@ -3293,8 +3288,8 @@ static void switchimpl (LexState *ls, int tk, void(*caselist)(LexState*,void*),
}
ls->fs->nactvar = nactvarend;

if (default_case != nullptr)
lgoto(ls, default_case, ls->getLineNumber());
if (default_pc != -1)
luaK_jumpto(fs, default_pc);

if (tk == TK_ARROW && fs->pinnedreg != -1) {
fs->pinnedreg = prevpinnedreg;
Expand Down
8 changes: 8 additions & 0 deletions testes/pluto/basic.pluto
Original file line number Diff line number Diff line change
Expand Up @@ -1303,6 +1303,14 @@ do
end
assert(f() == nil)
end
-- Possible infinite loop
assert(
switch 0 do
default -> switch 1 do
default -> true
end
end
)

print "Testing table freezing."
do
Expand Down

0 comments on commit 116304a

Please sign in to comment.