Skip to content

Commit

Permalink
fix: return proper nil on runtime.InstantiateModule errors (tetratela…
Browse files Browse the repository at this point in the history
…bs#2353)

Previously InstantiateModule could return a (*wasm.ModuleInstance)(nil)
instead of a proper nil value.

So callers could get a nil dereference panic in code like:

        m, _ := r.InstantiateModule(...)
        if m != nil {           // this check passes
                defer m.Close() // but this causes a panic
        }
  • Loading branch information
edman committed Dec 25, 2024
1 parent 610c202 commit 9b79c7e
Showing 1 changed file with 13 additions and 12 deletions.
25 changes: 13 additions & 12 deletions runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -289,8 +289,8 @@ func (r *runtime) InstantiateModule(
ctx context.Context,
compiled CompiledModule,
mConfig ModuleConfig,
) (mod api.Module, err error) {
if err = r.failIfClosed(); err != nil {
) (api.Module, error) {
if err := r.failIfClosed(); err != nil {
return nil, err
}

Expand All @@ -305,8 +305,9 @@ func (r *runtime) InstantiateModule(
}

var sysCtx *internalsys.Context
var err error
if sysCtx, err = config.toSysContext(); err != nil {
return
return nil, err
}

name := config.name
Expand All @@ -315,23 +316,23 @@ func (r *runtime) InstantiateModule(
}

// Instantiate the module.
mod, err = r.store.Instantiate(ctx, code.module, name, sysCtx, code.typeIDs)
mod, err := r.store.Instantiate(ctx, code.module, name, sysCtx, code.typeIDs)
if err != nil {
// If there was an error, don't leak the compiled module.
if code.closeWithModule {
_ = code.Close(ctx) // don't overwrite the error
}
return
return nil, err
}

if closeNotifier, ok := ctx.Value(expctxkeys.CloseNotifierKey{}).(experimentalapi.CloseNotifier); ok {
mod.(*wasm.ModuleInstance).CloseNotifier = closeNotifier
mod.CloseNotifier = closeNotifier
}

// Attach the code closer so that anything afterward closes the compiled
// code when closing the module.
if code.closeWithModule {
mod.(*wasm.ModuleInstance).CodeCloser = code
mod.CodeCloser = code
}

// Now, invoke any start functions, failing at first error.
Expand All @@ -340,20 +341,20 @@ func (r *runtime) InstantiateModule(
if start == nil {
continue
}
if _, err = start.Call(ctx); err != nil {
if _, err := start.Call(ctx); err != nil {
_ = mod.Close(ctx) // Don't leak the module on error.

if se, ok := err.(*sys.ExitError); ok {
if se.ExitCode() == 0 { // Don't err on success.
err = nil
return mod, nil
}
return // Don't wrap an exit error
return nil, err // Don't wrap an exit error
}
err = fmt.Errorf("module[%s] function[%s] failed: %w", name, fn, err)
return
return nil, err
}
}
return
return mod, nil
}

// Close implements api.Closer embedded in Runtime.
Expand Down

0 comments on commit 9b79c7e

Please sign in to comment.