Skip to content

Commit

Permalink
handle errors when calling NewContextFromSnapshot at V8 level
Browse files Browse the repository at this point in the history
  • Loading branch information
GustavoCaso committed Jan 27, 2022
1 parent 823e4da commit be2acf1
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 11 deletions.
12 changes: 6 additions & 6 deletions context.go
Expand Up @@ -8,7 +8,6 @@ package v8go
// #include "v8go.h"
import "C"
import (
"errors"
"runtime"
"sync"
"unsafe"
Expand Down Expand Up @@ -78,21 +77,22 @@ func NewContext(opt ...ContextOption) *Context {
}

// NewContextFromSnapshot creates a new JavaScript context from the Isolate startup data;
// If the Isolate has no startup data associated returns an error.
// error will be of type `JSError` if not nil.
func NewContextFromSnapshot(iso *Isolate, snapshot_index int) (*Context, error) {
ctxMutex.Lock()
ctxSeq++
ref := ctxSeq
ctxMutex.Unlock()

createParams := iso.createParams
if createParams == nil || createParams.startupData == nil {
return nil, errors.New("v8go: The isolate must have startupData associated with it")
rtn := C.NewContextFromSnapshot(iso.ptr, C.size_t(snapshot_index), C.int(ref))

if rtn.context == nil {
return nil, newJSError(rtn.error)
}

ctx := &Context{
ref: ref,
ptr: C.NewContextFromSnapshot(iso.ptr, C.size_t(snapshot_index), C.int(ref)),
ptr: rtn.context,
iso: iso,
}

Expand Down
39 changes: 39 additions & 0 deletions context_test.go
Expand Up @@ -55,6 +55,45 @@ func TestNewContextFromSnapshotErrorWhenIsolateHasNoStartupData(t *testing.T) {
}
}

func TestNewContextFromSnapshotErrorWhenIndexOutOfRange(t *testing.T) {
t.Parallel()

snapshotCreator := v8.NewSnapshotCreator()
snapshotCreatorIso, err := snapshotCreator.GetIsolate()
fatalIf(t, err)

snapshotCreatorCtx := v8.NewContext(snapshotCreatorIso)
defer snapshotCreatorCtx.Close()

snapshotCreatorCtx.RunScript(`const add = (a, b) => a + b`, "add.js")
snapshotCreatorCtx.RunScript(`function run() { return add(3, 4); }`, "main.js")
err = snapshotCreator.SetDefaultContext(snapshotCreatorCtx)
fatalIf(t, err)

snapshotCreatorCtx2 := v8.NewContext(snapshotCreatorIso)
defer snapshotCreatorCtx2.Close()

snapshotCreatorCtx2.RunScript(`const multiply = (a, b) => a * b`, "add.js")
snapshotCreatorCtx2.RunScript(`function run() { return multiply(3, 4); }`, "main.js")
index, err := snapshotCreator.AddContext(snapshotCreatorCtx2)
fatalIf(t, err)

data, err := snapshotCreator.Create(v8.FunctionCodeHandlingClear)
fatalIf(t, err)

iso := v8.NewIsolate(v8.WithStartupData(data))
defer iso.Dispose()

ctx, err := v8.NewContextFromSnapshot(iso, index+1)

if ctx != nil {
t.Errorf("expected nil context got: %+v", ctx)
}
if err == nil {
t.Error("error expected but was <nil>")
}
}

func TestJSExceptions(t *testing.T) {
t.Parallel()

Expand Down
20 changes: 16 additions & 4 deletions v8go.cc
Expand Up @@ -668,28 +668,40 @@ ContextPtr NewContext(IsolatePtr iso,
return ctx;
}

ContextPtr NewContextFromSnapshot(IsolatePtr iso,
RtnContext NewContextFromSnapshot(IsolatePtr iso,
size_t snapshot_blob_index,
int ref) {
Locker locker(iso);
Isolate::Scope isolate_scope(iso);
HandleScope handle_scope(iso);

RtnContext rtn = {};

// For function callbacks we need a reference to the context, but because of
// the complexities of C -> Go function pointers, we store a reference to the
// context as a simple integer identifier; this can then be used on the Go
// side to lookup the context in the context registry. We use slot 1 as slot 0
// has special meaning for the Chrome debugger.

Local<Context> local_ctx =
Context::FromSnapshot(iso, snapshot_blob_index).ToLocalChecked();
Local<Context> local_ctx;
MaybeLocal<Context> maybe_local_ctx =
Context::FromSnapshot(iso, snapshot_blob_index);

if (!maybe_local_ctx.ToLocal(&local_ctx)) {
RtnError error = {nullptr, nullptr, nullptr};
error.msg = CopyString("Failed to create context from snapshot index: " + std::to_string(snapshot_blob_index));
rtn.error = error;
return rtn;
}

local_ctx->SetEmbedderData(1, Integer::New(iso, ref));

m_ctx* ctx = new m_ctx;
ctx->ptr.Reset(iso, local_ctx);
ctx->iso = iso;
ctx->startup_data = nullptr;
return ctx;
rtn.context = ctx;
return rtn;
}

void ContextFree(ContextPtr ctx) {
Expand Down
7 changes: 6 additions & 1 deletion v8go.h
Expand Up @@ -124,6 +124,11 @@ typedef struct {
RtnError error;
} RtnValue;

typedef struct {
ContextPtr context;
RtnError error;
} RtnContext;

typedef struct {
const char* string;
RtnError error;
Expand Down Expand Up @@ -189,7 +194,7 @@ extern void CPUProfileDelete(CPUProfile* ptr);
extern ContextPtr NewContext(IsolatePtr iso_ptr,
TemplatePtr global_template_ptr,
int ref);
extern ContextPtr NewContextFromSnapshot(IsolatePtr iso,
extern RtnContext NewContextFromSnapshot(IsolatePtr iso,
size_t snapshot_blob_index,
int ref);
extern void ContextFree(ContextPtr ptr);
Expand Down

0 comments on commit be2acf1

Please sign in to comment.