Skip to content

Commit

Permalink
fix: prevent interpreter crash when using labeled break/continue in n…
Browse files Browse the repository at this point in the history
…ested loops
  • Loading branch information
jacopodl committed Oct 5, 2023
1 parent 212c24f commit 7bf9184
Show file tree
Hide file tree
Showing 3 changed files with 17 additions and 11 deletions.
20 changes: 11 additions & 9 deletions argon/lang/compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1258,7 +1258,9 @@ void Compiler::CompileJump(const parser::Unary *jump) {
if (jump->value != nullptr)
label = (String *) (((const Unary *) jump->value)->value);

if ((jb = this->unit_->FindLoop(label)) == nullptr) {
unsigned short pops;

if ((jb = this->unit_->FindLoop(label, pops)) == nullptr) {
ErrorFormat(kCompilerError[0], "unknown loop label, the loop '%s' cannot be %s",
ARGON_RAW_STRING((String *) ((const Unary *) jump->value)->value),
jump->token_type == scanner::TokenType::KW_BREAK ? "breaked" : "continued");
Expand All @@ -1269,19 +1271,19 @@ void Compiler::CompileJump(const parser::Unary *jump) {
dst = jb->end;

if (jump->token_type == scanner::TokenType::KW_BREAK) {
for (auto i = 0; i < jb->pops; i++)
for (auto i = 0; i < pops; i++)
this->unit_->Emit(vm::OpCode::POP, nullptr);

// Don't decrease the stack size
this->unit_->IncrementStack(jb->pops);
this->unit_->IncrementStack(pops);
} else if (jump->token_type == scanner::TokenType::KW_CONTINUE) {
if (jb != this->unit_->jstack) {
for (auto i = 0; i < jb->pops; i++)
this->unit_->Emit(vm::OpCode::POP, nullptr);
pops -= jb->pops;

// Don't decrease the stack size
this->unit_->IncrementStack(jb->pops);
}
for (auto i = 0; i < pops; i++)
this->unit_->Emit(vm::OpCode::POP, nullptr);

// Don't decrease the stack size
this->unit_->IncrementStack(pops);

dst = jb->start;
}
Expand Down
6 changes: 5 additions & 1 deletion argon/lang/translation_unit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -235,8 +235,12 @@ JBlock *TranslationUnit::JBNew(BasicBlock *start, BasicBlock *end, unsigned shor
return jb;
}

JBlock *TranslationUnit::FindLoop(String *label) const {
JBlock *TranslationUnit::FindLoop(String *label, unsigned short &pops) const {
pops = 0;

for (JBlock *block = this->jstack; block != nullptr; block = block->prev) {
pops += block->pops;

if (block->type != JBlockType::LOOP)
continue;

Expand Down
2 changes: 1 addition & 1 deletion argon/lang/translation_unit.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ namespace argon::lang {

JBlock *JBNew(BasicBlock *start, BasicBlock *end, unsigned short pops);

JBlock *FindLoop(vm::datatype::String *label) const;
JBlock *FindLoop(vm::datatype::String *label, unsigned short &pops) const;

unsigned int ComputeAssemblyLength(unsigned int *out_linfo_sz) const;

Expand Down

0 comments on commit 7bf9184

Please sign in to comment.