Skip to content

Commit

Permalink
Merge pull request #1364 from onflow/supun/handle-crashers-v0.20
Browse files Browse the repository at this point in the history
[v0.20] Gracefully handle cadence crashes/panics
  • Loading branch information
SupunS authored Jan 18, 2022
2 parents 47d3eec + 9e3506f commit fe92278
Show file tree
Hide file tree
Showing 2 changed files with 388 additions and 44 deletions.
94 changes: 87 additions & 7 deletions runtime/runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,24 @@ func NewInterpreterRuntime(options ...Option) Runtime {
return runtime
}

func (r *interpreterRuntime) Recover(onError func(error), context Context) {
recovered := recover()
if recovered == nil {
return
}

var err error
switch recovered := recovered.(type) {
case Error:
// avoid redundant wrapping
err = recovered
case error:
err = newError(recovered, context)
}

onError(err)
}

func (r *interpreterRuntime) SetCoverageReport(coverageReport *CoverageReport) {
r.coverageReport = coverageReport
}
Expand All @@ -194,7 +212,14 @@ func (r *interpreterRuntime) SetAtreeValidationEnabled(enabled bool) {
r.atreeValidationEnabled = enabled
}

func (r *interpreterRuntime) ExecuteScript(script Script, context Context) (cadence.Value, error) {
func (r *interpreterRuntime) ExecuteScript(script Script, context Context) (val cadence.Value, err error) {
defer r.Recover(
func(internalErr error) {
err = internalErr
},
context,
)

context.InitializeCodesAndPrograms()

storage := r.newStorage(context.Interface)
Expand Down Expand Up @@ -431,7 +456,14 @@ func (r *interpreterRuntime) InvokeContractFunction(
arguments []interpreter.Value,
argumentTypes []sema.Type,
context Context,
) (cadence.Value, error) {
) (val cadence.Value, err error) {
defer r.Recover(
func(internalErr error) {
err = internalErr
},
context,
)

context.InitializeCodesAndPrograms()

storage := r.newStorage(context.Interface)
Expand Down Expand Up @@ -558,7 +590,14 @@ func (r *interpreterRuntime) convertArgument(
return argument
}

func (r *interpreterRuntime) ExecuteTransaction(script Script, context Context) error {
func (r *interpreterRuntime) ExecuteTransaction(script Script, context Context) (err error) {
defer r.Recover(
func(internalErr error) {
err = internalErr
},
context,
)

context.InitializeCodesAndPrograms()

storage := r.newStorage(context.Interface)
Expand Down Expand Up @@ -847,7 +886,20 @@ func hasValidStaticType(value interpreter.Value) bool {
// ParseAndCheckProgram parses the given code and checks it.
// Returns a program that can be interpreted (AST + elaboration).
//
func (r *interpreterRuntime) ParseAndCheckProgram(code []byte, context Context) (*interpreter.Program, error) {
func (r *interpreterRuntime) ParseAndCheckProgram(
code []byte,
context Context,
) (
program *interpreter.Program,
err error,
) {
defer r.Recover(
func(internalErr error) {
err = internalErr
},
context,
)

context.InitializeCodesAndPrograms()

storage := r.newStorage(context.Interface)
Expand All @@ -862,7 +914,7 @@ func (r *interpreterRuntime) ParseAndCheckProgram(code []byte, context Context)
checkerOptions,
)

program, err := r.parseAndCheckProgram(
program, err = r.parseAndCheckProgram(
code,
context,
functions,
Expand Down Expand Up @@ -2733,7 +2785,21 @@ func (r *interpreterRuntime) executeNonProgram(interpret interpretFunc, context
return exportValue(value)
}

func (r *interpreterRuntime) ReadStored(address common.Address, path cadence.Path, context Context) (cadence.Value, error) {
func (r *interpreterRuntime) ReadStored(
address common.Address,
path cadence.Path,
context Context,
) (
val cadence.Value,
err error,
) {
defer r.Recover(
func(internalErr error) {
err = internalErr
},
context,
)

return r.executeNonProgram(
func(inter *interpreter.Interpreter) (interpreter.Value, error) {
key := interpreter.PathToStorageKey(importPathValue(path))
Expand All @@ -2744,7 +2810,21 @@ func (r *interpreterRuntime) ReadStored(address common.Address, path cadence.Pat
)
}

func (r *interpreterRuntime) ReadLinked(address common.Address, path cadence.Path, context Context) (cadence.Value, error) {
func (r *interpreterRuntime) ReadLinked(
address common.Address,
path cadence.Path,
context Context,
) (
val cadence.Value,
err error,
) {
defer r.Recover(
func(internalErr error) {
err = internalErr
},
context,
)

return r.executeNonProgram(
func(inter *interpreter.Interpreter) (interpreter.Value, error) {
key, _, err := inter.GetCapabilityFinalTargetStorageKey(
Expand Down
Loading

0 comments on commit fe92278

Please sign in to comment.