Skip to content

Commit 8497b78

Browse files
committed
Merge pull request #366 from bpowers/master
compiler: fix runtime exceptions with blocking deferred functions
2 parents ccad700 + 6986031 commit 8497b78

File tree

2 files changed

+49
-1
lines changed

2 files changed

+49
-1
lines changed

compiler/statements.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,13 @@ func (c *funcContext) translateStmt(stmt ast.Stmt, label *types.Label) {
282282
}
283283
results = c.resultNames
284284
}
285-
c.Printf("return%s;", c.translateResults(results))
285+
rVal := c.translateResults(results)
286+
if c.Flattened[s] {
287+
resumeCase := c.caseCounter
288+
c.caseCounter++
289+
c.Printf("/* */ $s = %[1]d; case %[1]d:", resumeCase)
290+
}
291+
c.Printf("return%s;", rVal)
286292

287293
case *ast.DeferStmt:
288294
isBuiltin := false

tests/deferblock_test.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package tests
2+
3+
import (
4+
"testing"
5+
"time"
6+
)
7+
8+
func inner(ch chan struct{}, b bool) ([]byte, error) {
9+
// ensure gopherjs thinks that this inner function can block
10+
if b {
11+
<-ch
12+
}
13+
return []byte{}, nil
14+
}
15+
16+
// this function's call to inner never blocks, but the deferred
17+
// statement does.
18+
func outer(ch chan struct{}, b bool) ([]byte, error) {
19+
defer func() {
20+
<-ch
21+
}()
22+
23+
return inner(ch, b)
24+
}
25+
26+
func TestBlockingInDefer(t *testing.T) {
27+
defer func() {
28+
if x := recover(); x != nil {
29+
t.Error("run time panic: %v", x)
30+
}
31+
}()
32+
33+
ch := make(chan struct{})
34+
b := false
35+
36+
go func() {
37+
time.Sleep(5 * time.Millisecond)
38+
ch <- struct{}{}
39+
}()
40+
41+
outer(ch, b)
42+
}

0 commit comments

Comments
 (0)