Skip to content

Commit

Permalink
- Fixed iterator stack leak when returning from the loop body. Fixes #…
Browse files Browse the repository at this point in the history
…148.

- Fixed stack leak when 'if' statement with value is last.
  • Loading branch information
dop251 committed Apr 14, 2020
1 parent 0cd29d8 commit 77e84ff
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 11 deletions.
3 changes: 2 additions & 1 deletion compiler.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (

const (
blockLoop = iota
blockLoopEnum
blockTry
blockBranch
blockSwitch
Expand Down Expand Up @@ -85,7 +86,7 @@ func (c *compiler) leaveBlock() {
for _, item := range c.block.breaks {
c.p.code[item] = jump(lbl - item)
}
if c.block.typ == blockLoop {
if t := c.block.typ; t == blockLoop || t == blockLoopEnum {
for _, item := range c.block.conts {
c.p.code[item] = jump(c.block.cont - item)
}
Expand Down
27 changes: 17 additions & 10 deletions compiler_stmt.go
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ func (c *compiler) compileForInStatement(v *ast.ForInStatement, needResult bool)

func (c *compiler) compileLabeledForInStatement(v *ast.ForInStatement, needResult bool, label string) {
c.block = &block{
typ: blockLoop,
typ: blockLoopEnum,
outer: c.block,
label: label,
needResult: needResult,
Expand Down Expand Up @@ -421,15 +421,15 @@ func (c *compiler) findBranchBlock(st *ast.BranchStatement) *block {
func (c *compiler) findContinueBlock(label *ast.Identifier) (block *block) {
if label != nil {
for b := c.block; b != nil; b = b.outer {
if b.typ == blockLoop && b.label == label.Name {
if (b.typ == blockLoop || b.typ == blockLoopEnum) && b.label == label.Name {
block = b
break
}
}
} else {
// find the nearest loop
for b := c.block; b != nil; b = b.outer {
if b.typ == blockLoop {
if b.typ == blockLoop || b.typ == blockLoopEnum {
block = b
break
}
Expand All @@ -452,7 +452,7 @@ func (c *compiler) findBreakBlock(label *ast.Identifier) (block *block) {
L:
for b := c.block; b != nil; b = b.outer {
switch b.typ {
case blockLoop, blockSwitch:
case blockLoop, blockLoopEnum, blockSwitch:
block = b
break L
}
Expand Down Expand Up @@ -486,7 +486,7 @@ func (c *compiler) compileBreak(label *ast.Identifier, idx file.Idx) {
c.emit(halt)
case blockWith:
c.emit(leaveWith)
case blockLoop, blockSwitch:
case blockLoop, blockLoopEnum, blockSwitch:
block = b
break L
}
Expand All @@ -510,7 +510,7 @@ func (c *compiler) compileContinue(label *ast.Identifier, idx file.Idx) {
for b := c.block; b != nil; b = b.outer {
if b.typ == blockTry {
c.emit(halt)
} else if b.typ == blockLoop && b.label == label.Name {
} else if (b.typ == blockLoop || b.typ == blockLoopEnum) && b.label == label.Name {
block = b
break
}
Expand All @@ -520,7 +520,7 @@ func (c *compiler) compileContinue(label *ast.Identifier, idx file.Idx) {
for b := c.block; b != nil; b = b.outer {
if b.typ == blockTry {
c.emit(halt)
} else if b.typ == blockLoop {
} else if b.typ == blockLoop || b.typ == blockLoopEnum {
block = b
break
}
Expand Down Expand Up @@ -587,10 +587,14 @@ func (c *compiler) compileIfStatement(v *ast.IfStatement, needResult bool) {
c.p.code[jmp1] = jump(len(c.p.code) - jmp1)
c.markBlockStart()
} else {
c.p.code[jmp] = jne(len(c.p.code) - jmp)
c.markBlockStart()
if needResult {
c.emit(jump(2))
c.p.code[jmp] = jne(len(c.p.code) - jmp)
c.emit(loadUndef)
c.markBlockStart()
} else {
c.p.code[jmp] = jne(len(c.p.code) - jmp)
c.markBlockStart()
}
}
}
Expand All @@ -603,8 +607,11 @@ func (c *compiler) compileReturnStatement(v *ast.ReturnStatement) {
c.emit(loadUndef)
}
for b := c.block; b != nil; b = b.outer {
if b.typ == blockTry {
switch b.typ {
case blockTry:
c.emit(halt)
case blockLoopEnum:
c.emit(enumPop)
}
}
c.emit(ret)
Expand Down
25 changes: 25 additions & 0 deletions compiler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ func testScript1(script string, expectedResult Value, t *testing.T) {
if vm.sp != 0 {
t.Fatalf("sp: %d", vm.sp)
}

if l := len(vm.iterStack); l > 0 {
t.Fatalf("iter stack is not empty: %d", l)
}
}

func TestEmptyProgram(t *testing.T) {
Expand Down Expand Up @@ -1968,6 +1972,27 @@ func TestEmptyCodeError(t *testing.T) {
}
}

func TestReturnFromForInLoop(t *testing.T) {
const SCRIPT = `
(function f() {
for (var i in {a: 1}) {
return true;
}
})();
`
testScript1(SCRIPT, valueTrue, t)
}

func TestIfStackLeaks(t *testing.T) {
const SCRIPT = `
var t = 0;
if (t === 0) {
t;
}
`
testScript1(SCRIPT, _positiveZero, t)
}

// FIXME
/*
func TestDummyCompile(t *testing.T) {
Expand Down
8 changes: 8 additions & 0 deletions tc39_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,14 @@ func (ctx *tc39TestCtx) runTC39Test(name, src string, meta *tc39Meta, t testing.
t.Fatalf("%s: Expected error: %v", name, err)
}
}

if vm.vm.sp != 0 {
t.Fatalf("sp: %d", vm.vm.sp)
}

if l := len(vm.vm.iterStack); l > 0 {
t.Fatalf("iter stack is not empty: %d", l)
}
}

func (ctx *tc39TestCtx) runTC39File(name string, t testing.TB) {
Expand Down

0 comments on commit 77e84ff

Please sign in to comment.