Problem
Guest-defined resource destructors are registered through a lazy resolver, but resolution failure is silently treated as “no destructor”:
func resourceDtor(resolve func() api.Function) func(context.Context, uint32) error {
return func(ctx context.Context, rep uint32) error {
fn := resolve()
if fn == nil {
return nil
}
...
}
}
resolveDefinedResourceDtors likewise describes unresolved destructors as best-effort and deliberately skips them rather than failing instantiation/drop.
Relevant code:
Impact
A resource type that declares a destructor has observable cleanup semantics. If its function index is malformed, validation must reject the component. If the function is valid but unavailable because the graph has not instantiated its defining module yet, dropping the resource cannot be treated as successful—the representation is removed while required guest cleanup never runs.
This can leak guest-managed state, skip security-sensitive cleanup, and make a malformed or incorrectly ordered graph appear to execute successfully.
Suggested fix
- Validate every
ResourceDesc.Dtor index and core function signature during component validation/graph construction.
- Preserve lazy lookup only for initialization ordering, but return a trap/error when a declared destructor is still unavailable at drop time.
- Do not remove the handle and report success as though the resource had no destructor.
- Make the unavailable-before-module-instantiation case explicit: either graph ordering guarantees availability before the first possible drop, or an attempted early drop traps deterministically.
Regression tests
- An out-of-range destructor function index must reject the component before instantiation mutates runtime state.
- A valid destructor increments observable state exactly once on drop.
- A destructor unavailable during an early core start must trap/fail instantiation, never silently succeed.
- A trapping destructor must poison the instance and must not be rerun by a later drop/close.
- Nested resource transfer must still invoke the defining component's destructor.
Problem
Guest-defined resource destructors are registered through a lazy resolver, but resolution failure is silently treated as “no destructor”:
resolveDefinedResourceDtorslikewise describes unresolved destructors as best-effort and deliberately skips them rather than failing instantiation/drop.Relevant code:
Impact
A resource type that declares a destructor has observable cleanup semantics. If its function index is malformed, validation must reject the component. If the function is valid but unavailable because the graph has not instantiated its defining module yet, dropping the resource cannot be treated as successful—the representation is removed while required guest cleanup never runs.
This can leak guest-managed state, skip security-sensitive cleanup, and make a malformed or incorrectly ordered graph appear to execute successfully.
Suggested fix
ResourceDesc.Dtorindex and core function signature during component validation/graph construction.Regression tests