Skip to content

Commit

Permalink
Merge pull request #245 from goplus/go
Browse files Browse the repository at this point in the history
ssa.Go: check PanicError if set ctx.RunContext
  • Loading branch information
visualfc authored Jun 7, 2023
2 parents e374d19 + 280830b commit bdb96f2
Show file tree
Hide file tree
Showing 6 changed files with 46 additions and 13 deletions.
6 changes: 3 additions & 3 deletions builtin.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ func (inter *Interp) callBuiltin(caller *frame, fn *ssa.Builtin, args []value, s
case "panic":
// ssa.Panic handles most cases; this is only for "go
// panic" or "defer panic".
panic(PanicError{fr: caller, Value: args[0]})
panic(PanicError{stack: debugStack(caller), Value: args[0]})

case "recover":
return doRecover(caller)
Expand Down Expand Up @@ -284,7 +284,7 @@ func (inter *Interp) callBuiltinDiscardsResult(caller *frame, fn *ssa.Builtin, a
case "panic":
// ssa.Panic handles most cases; this is only for "go
// panic" or "defer panic".
panic(PanicError{fr: caller, Value: args[0]})
panic(PanicError{stack: debugStack(caller), Value: args[0]})

case "recover":
doRecover(caller)
Expand Down Expand Up @@ -436,7 +436,7 @@ func (interp *Interp) callBuiltinByStack(caller *frame, fn string, ssaArgs []ssa
// ssa.Panic handles most cases; this is only for "go
// panic" or "defer panic".
arg0 := caller.reg(ia[0])
panic(PanicError{fr: caller, Value: arg0})
panic(PanicError{stack: debugStack(caller), Value: arg0})

case "recover":
caller.setReg(ir, doRecover(caller))
Expand Down
4 changes: 3 additions & 1 deletion cmd/internal/run/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
package run

import (
"context"
"fmt"
"log"
"os"
Expand Down Expand Up @@ -77,6 +78,7 @@ func runCmd(cmd *base.Command, args []string) {
}
ctx := igop.NewContext(mode)
ctx.BuildContext = base.BuildContext
ctx.RunContext = context.TODO()
var pkg *ssa.Package
var input string
if isDir {
Expand Down Expand Up @@ -108,7 +110,7 @@ func runCmd(cmd *base.Command, args []string) {
code, err := ctx.RunInterp(interp, input, args)
if err != nil {
if e, ok := err.(igop.PanicError); ok {
fmt.Fprintf(os.Stderr, "panic: %v\n", e)
fmt.Fprintf(os.Stderr, "panic: %v\n\n%s\n", e.Error(), e.Stack())
} else {
fmt.Fprintln(os.Stderr, err)
}
Expand Down
10 changes: 10 additions & 0 deletions context.go
Original file line number Diff line number Diff line change
Expand Up @@ -533,6 +533,7 @@ func (p *Context) runInterpWithContext(interp *Interp, input string, args []stri
var exitCode int
var err error
ch := make(chan error, 1)
interp.cherror = make(chan PanicError)
go func() {
exitCode, err = p.runInterp(interp, input, args)
ch <- err
Expand All @@ -548,6 +549,15 @@ func (p *Context) runInterpWithContext(interp *Interp, input string, args []stri
err = ctx.Err()
}
case err = <-ch:
case e := <-interp.cherror:
switch v := e.Value.(type) {
case exitPanic:
exitCode = int(v)
default:
err = e
interp.Abort()
exitCode = 2
}
}
return exitCode, err
}
Expand Down
5 changes: 3 additions & 2 deletions interp.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ type Interp struct {
funcs map[*ssa.Function]*function // ssa.Function -> *function
msets map[reflect.Type](map[string]*ssa.Function) // user defined type method sets
chexit chan int // call os.Exit code by chan for runtime.Goexit
cherror chan PanicError // call by go func error for context
deferMap sync.Map // defer goroutine id -> call frame
rfuncMap sync.Map // reflect.Value(fn).Pointer -> *function
typesMutex sync.RWMutex // findType/toType mutex
Expand Down Expand Up @@ -376,7 +377,7 @@ func (fr *frame) gc() {
}

func (fr *frame) valid() bool {
return fr != nil && fr.pfn != nil
return fr != nil && fr.pfn != nil && fr.block != nil
}

func (fr *frame) pc() uintptr {
Expand Down Expand Up @@ -1285,7 +1286,7 @@ func (i *Interp) RunFunc(name string, args ...Value) (r Value, err error) {
for pfr.callee != nil {
pfr = pfr.callee
}
err = PanicError{fr: pfr, Value: p}
err = PanicError{stack: debugStack(pfr), Value: p}
}
}()
if fn := i.mainpkg.Func(name); fn != nil {
Expand Down
30 changes: 25 additions & 5 deletions opblock.go
Original file line number Diff line number Diff line change
Expand Up @@ -912,17 +912,37 @@ func makeInstr(interp *Interp, pfn *function, instr ssa.Instruction) func(fr *fr
case *ssa.Panic:
ix := pfn.regIndex(instr.X)
return func(fr *frame) {
panic(PanicError{Value: fr.reg(ix), fr: fr})
panic(PanicError{stack: debugStack(fr), Value: fr.reg(ix)})
}
case *ssa.Go:
iv, ia, ib := getCallIndex(pfn, &instr.Call)
return func(fr *frame) {
fn, args := interp.prepareCall(fr, &instr.Call, iv, ia, ib)
atomic.AddInt32(&interp.goroutines, 1)
go func() {
interp.callDiscardsResult(&frame{}, fn, args, instr.Call.Args)
atomic.AddInt32(&interp.goroutines, -1)
}()
if interp.ctx.RunContext != nil {
go func() {
root := &frame{interp: interp}
switch f := fn.(type) {
case *ssa.Function:
root.pfn = interp.funcs[f]
case *closure:
root.pfn = f.pfn
}
defer func() {
e := recover()
if e != nil {
interp.cherror <- PanicError{stack: debugStack(root), Value: e}
}
}()
interp.callDiscardsResult(root, fn, args, instr.Call.Args)
atomic.AddInt32(&interp.goroutines, -1)
}()
} else {
go func() {
interp.callDiscardsResult(&frame{}, fn, args, instr.Call.Args)
atomic.AddInt32(&interp.goroutines, -1)
}()
}
}
case *ssa.Defer:
iv, ia, ib := getCallIndex(pfn, &instr.Call)
Expand Down
4 changes: 2 additions & 2 deletions ops.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import (

// If the target program panics, the interpreter panics with this type.
type PanicError struct {
fr *frame
stack []byte
Value value
}

Expand All @@ -29,7 +29,7 @@ func (p PanicError) Error() string {
}

func (p PanicError) Stack() []byte {
return debugStack(p.fr)
return p.stack
}

// If the target program calls exit, the interpreter panics with this type.
Expand Down

0 comments on commit bdb96f2

Please sign in to comment.