diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e69fdb76..118213ad5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Add some missing error propagation +- Fix crash from template finalizer releasing V8 data, let it be disposed with the isolate +- Fix crash by keeping alive the template while its C++ pointer is still being used ## [v0.6.0] - 2021-05-11 diff --git a/context.go b/context.go index c7c774456..761b3cab4 100644 --- a/context.go +++ b/context.go @@ -8,6 +8,7 @@ package v8go // #include "v8go.h" import "C" import ( + "runtime" "sync" "unsafe" ) @@ -72,6 +73,7 @@ func NewContext(opt ...ContextOption) *Context { ptr: C.NewContext(opts.iso.ptr, opts.gTmpl.ptr, C.int(ref)), iso: opts.iso, } + runtime.KeepAlive(opts.gTmpl) return ctx } diff --git a/function_template.go b/function_template.go index 530c7b334..5fad38088 100644 --- a/function_template.go +++ b/function_template.go @@ -66,6 +66,7 @@ func NewFunctionTemplate(iso *Isolate, callback FunctionCallback) *FunctionTempl // GetFunction returns an instance of this function template bound to the given context. func (tmpl *FunctionTemplate) GetFunction(ctx *Context) *Function { rtn := C.FunctionTemplateGetFunction(tmpl.ptr, ctx.ptr) + runtime.KeepAlive(tmpl) val, err := valueResult(ctx, rtn) if err != nil { panic(err) // TODO: Consider returning the error diff --git a/object_template.go b/object_template.go index ad833a049..4b7f677fa 100644 --- a/object_template.go +++ b/object_template.go @@ -56,6 +56,7 @@ func (o *ObjectTemplate) NewInstance(ctx *Context) (*Object, error) { } rtn := C.ObjectTemplateNewInstance(o.ptr, ctx.ptr) + runtime.KeepAlive(o) return objectResult(ctx, rtn) } diff --git a/template.go b/template.go index 7b399f441..5a12a7ccd 100644 --- a/template.go +++ b/template.go @@ -42,8 +42,10 @@ func (t *template) Set(name string, val interface{}, attributes ...PropertyAttri C.TemplateSetValue(t.ptr, cname, newVal.ptr, C.int(attrs)) case *ObjectTemplate: C.TemplateSetTemplate(t.ptr, cname, v.ptr, C.int(attrs)) + runtime.KeepAlive(v) case *FunctionTemplate: C.TemplateSetTemplate(t.ptr, cname, v.ptr, C.int(attrs)) + runtime.KeepAlive(v) case *Value: if v.IsObject() || v.IsExternal() { return errors.New("v8go: unsupported property: value type must be a primitive or use a template") @@ -52,12 +54,15 @@ func (t *template) Set(name string, val interface{}, attributes ...PropertyAttri default: return fmt.Errorf("v8go: unsupported property type `%T`, must be one of string, int32, uint32, int64, uint64, float64, *big.Int, *v8go.Value, *v8go.ObjectTemplate or *v8go.FunctionTemplate", v) } + runtime.KeepAlive(t) return nil } func (t *template) finalizer() { - C.TemplateFree(t.ptr) + // Using v8::PersistentBase::Reset() wouldn't be thread-safe to do from + // this finalizer goroutine so just free the wrapper and let the template + // itself get cleaned up when the isolate is disposed. + C.TemplateFreeWrapper(t.ptr) t.ptr = nil - runtime.SetFinalizer(t, nil) } diff --git a/v8go.cc b/v8go.cc index 1d1bd746e..7f5f36ade 100644 --- a/v8go.cc +++ b/v8go.cc @@ -213,8 +213,9 @@ IsolateHStatistics IsolationGetHeapStatistics(IsolatePtr iso) { HandleScope handle_scope(iso); \ Local