Skip to content

Commit

Permalink
Merge pull request #277 from Hywan/fix-instance-leak
Browse files Browse the repository at this point in the history
fix: Force finalizers to explore the graph of objects
  • Loading branch information
Hywan committed Jul 8, 2021
2 parents 811a013 + 6c8c75f commit 72b0251
Show file tree
Hide file tree
Showing 7 changed files with 111 additions and 27 deletions.
20 changes: 17 additions & 3 deletions wasmer/exports.go
Expand Up @@ -20,9 +20,8 @@ func newExports(instance *C.wasm_instance_t, module *Module) *Exports {
self := &Exports{}
C.wasm_instance_exports(instance, &self._inner)

runtime.KeepAlive(instance)
runtime.SetFinalizer(self, func(exports *Exports) {
C.wasm_extern_vec_delete(exports.inner())
runtime.SetFinalizer(self, func(self *Exports) {
self.Close()
})

numberOfExports := int(self.inner().size)
Expand Down Expand Up @@ -196,3 +195,18 @@ func (self *Exports) GetWasiStartFunction() (NativeFunction, error) {

return newFunction(start, nil, nil).Native(), nil
}

// Force to close the Exports.
//
// A runtime finalizer is registered on the Exports, but it is
// possible to force the destruction of the Exports by calling Close
// manually.
func (self *Exports) Close() {
runtime.SetFinalizer(self, nil)

for extern := range self.exports {
delete(self.exports, extern)
}

C.wasm_extern_vec_delete(&self._inner)
}
22 changes: 18 additions & 4 deletions wasmer/exporttype.go
Expand Up @@ -16,9 +16,8 @@ func newExportTypes(module *Module) *exportTypes {
self := &exportTypes{}
C.wasm_module_exports(module.inner(), &self._inner)

runtime.KeepAlive(module)
runtime.SetFinalizer(self, func(self *exportTypes) {
C.wasm_exporttype_vec_delete(self.inner())
self.close()
})

numberOfExportTypes := int(self.inner().size)
Expand All @@ -43,6 +42,11 @@ func (self *exportTypes) inner() *C.wasm_exporttype_vec_t {
return &self._inner
}

func (self *exportTypes) close() {
runtime.SetFinalizer(self, nil)
C.wasm_exporttype_vec_delete(&self._inner)
}

// ExportType is a descriptor for an exported WebAssembly value.
type ExportType struct {
_inner *C.wasm_exporttype_t
Expand All @@ -53,8 +57,8 @@ func newExportType(pointer *C.wasm_exporttype_t, ownedBy interface{}) *ExportTyp
exportType := &ExportType{_inner: pointer, _ownedBy: ownedBy}

if ownedBy == nil {
runtime.SetFinalizer(exportType, func(exportType *ExportType) {
C.wasm_exporttype_delete(exportType.inner())
runtime.SetFinalizer(exportType, func(self *ExportType) {
self.Close()
})
}

Expand Down Expand Up @@ -116,3 +120,13 @@ func (self *ExportType) Type() *ExternType {

return newExternType(ty, self.ownedBy())
}

// Force to close the ExportType.
//
// A runtime finalizer is registered on the ExportType, but it is
// possible to force the destruction of the ExportType by calling
// Close manually.
func (self *ExportType) Close() {
runtime.SetFinalizer(self, nil)
C.wasm_exporttype_delete(self.inner())
}
8 changes: 4 additions & 4 deletions wasmer/function.go
Expand Up @@ -46,12 +46,12 @@ func newFunction(pointer *C.wasm_func_t, environment *functionEnvironment, owned
}

if ownedBy == nil {
runtime.SetFinalizer(function, func(function *Function) {
if function.environment != nil {
hostFunctionStore.remove(function.environment.hostFunctionStoreIndex)
runtime.SetFinalizer(function, func(self *Function) {
if self.environment != nil {
hostFunctionStore.remove(self.environment.hostFunctionStoreIndex)
}

C.wasm_func_delete(function.inner())
C.wasm_func_delete(self.inner())
})
}

Expand Down
22 changes: 18 additions & 4 deletions wasmer/importtype.go
Expand Up @@ -16,9 +16,8 @@ func newImportTypes(module *Module) *importTypes {
self := &importTypes{}
C.wasm_module_imports(module.inner(), &self._inner)

runtime.KeepAlive(module)
runtime.SetFinalizer(self, func(self *importTypes) {
C.wasm_importtype_vec_delete(self.inner())
self.close()
})

numberOfImportTypes := int(self.inner().size)
Expand All @@ -43,6 +42,11 @@ func (self *importTypes) inner() *C.wasm_importtype_vec_t {
return &self._inner
}

func (self *importTypes) close() {
runtime.SetFinalizer(self, nil)
C.wasm_importtype_vec_delete(&self._inner)
}

// ImportType is a descriptor for an imported value into a WebAssembly
// module.
type ImportType struct {
Expand All @@ -54,8 +58,8 @@ func newImportType(pointer *C.wasm_importtype_t, ownedBy interface{}) *ImportTyp
importType := &ImportType{_inner: pointer, _ownedBy: ownedBy}

if ownedBy == nil {
runtime.SetFinalizer(importType, func(importType *ImportType) {
C.wasm_importtype_delete(importType.inner())
runtime.SetFinalizer(importType, func(self *ImportType) {
self.Close()
})
}

Expand Down Expand Up @@ -143,3 +147,13 @@ func (self *ImportType) Type() *ExternType {

return newExternType(ty, self.ownedBy())
}

// Force to close the ImportType.
//
// A runtime finalizer is registered on the ImportType, but it is
// possible to force the destruction of the ImportType by calling
// Close manually.
func (self *ImportType) Close() {
runtime.SetFinalizer(self, nil)
C.wasm_importtype_delete(self.inner())
}
17 changes: 12 additions & 5 deletions wasmer/instance.go
Expand Up @@ -51,10 +51,6 @@ func NewInstance(module *Module, imports *ImportObject) (*Instance, error) {
return nil, err2
}

runtime.KeepAlive(module)
runtime.KeepAlive(module.store)
runtime.KeepAlive(imports)

if traps != nil {
return nil, newErrorFromTrap(traps)
}
Expand All @@ -66,7 +62,7 @@ func NewInstance(module *Module, imports *ImportObject) (*Instance, error) {
}

runtime.SetFinalizer(self, func(self *Instance) {
C.wasm_instance_delete(self.inner())
self.Close()
})

return self, nil
Expand All @@ -75,3 +71,14 @@ func NewInstance(module *Module, imports *ImportObject) (*Instance, error) {
func (self *Instance) inner() *C.wasm_instance_t {
return self._inner
}

// Force to close the Instance.
//
// A runtime finalizer is registered on the Instance, but it is
// possible to force the destruction of the Instance by calling Close
// manually.
func (self *Instance) Close() {
runtime.SetFinalizer(self, nil)
C.wasm_instance_delete(self.inner())
self.Exports.Close()
}
38 changes: 32 additions & 6 deletions wasmer/module.go
Expand Up @@ -53,6 +53,10 @@ import (
type Module struct {
_inner *C.wasm_module_t
store *Store
// Stored if computed to avoid further reallocations.
importTypes *importTypes
// Stored if computed to avoid further reallocations.
exportTypes *exportTypes
}

// NewModule instantiates a new Module with the given Store.
Expand Down Expand Up @@ -93,10 +97,8 @@ func NewModule(store *Store, bytes []byte) (*Module, error) {
return nil, err2
}

runtime.KeepAlive(bytes)
runtime.KeepAlive(wasmBytes)
runtime.SetFinalizer(self, func(self *Module) {
C.wasm_module_delete(self.inner())
self.Close()
})

return self, nil
Expand Down Expand Up @@ -175,7 +177,11 @@ func (self *Module) Name() string {
// module, _ := wasmer.NewModule(store, wasmBytes)
// imports := module.Imports()
func (self *Module) Imports() []*ImportType {
return newImportTypes(self).importTypes
if nil == self.importTypes {
self.importTypes = newImportTypes(self)
}

return self.importTypes.importTypes
}

// Exports returns the Module's exports as an ExportType array.
Expand All @@ -186,7 +192,11 @@ func (self *Module) Imports() []*ImportType {
// module, _ := wasmer.NewModule(store, wasmBytes)
// exports := module.Exports()
func (self *Module) Exports() []*ExportType {
return newExportTypes(self).exportTypes
if nil == self.exportTypes {
self.exportTypes = newExportTypes(self)
}

return self.exportTypes.exportTypes
}

// Serialize serializes the module and returns the Wasm code as an byte array.
Expand Down Expand Up @@ -247,10 +257,26 @@ func DeserializeModule(store *Store, bytes []byte) (*Module, error) {
return nil, err
}

runtime.KeepAlive(bytes)
runtime.SetFinalizer(self, func(self *Module) {
C.wasm_module_delete(self.inner())
})

return self, nil
}

// Force to close the Module.
//
// A runtime finalizer is registered on the Module, but it is possible
// to force the destruction of the Module by calling Close manually.
func (self *Module) Close() {
runtime.SetFinalizer(self, nil)
C.wasm_module_delete(self.inner())

if nil != self.importTypes {
self.importTypes.close()
}

if nil != self.exportTypes {
self.exportTypes.close()
}
}
11 changes: 10 additions & 1 deletion wasmer/store.go
Expand Up @@ -31,7 +31,7 @@ func NewStore(engine *Engine) *Store {
}

runtime.SetFinalizer(self, func(self *Store) {
C.wasm_store_delete(self.inner())
self.Close()
})

return self
Expand All @@ -40,3 +40,12 @@ func NewStore(engine *Engine) *Store {
func (self *Store) inner() *C.wasm_store_t {
return self._inner
}

// Force to close the Store.
//
// A runtime finalizer is registered on the Store, but it is possible
// to force the destruction of the Store by calling Close manually.
func (self *Store) Close() {
runtime.SetFinalizer(self, nil)
C.wasm_store_delete(self.inner())
}

0 comments on commit 72b0251

Please sign in to comment.