Ryanzyy
Ryanzyy

Reputation: 101

V8 - Node C++ Addon - Throwing Exception in a ConstructCall causes "FATAL ERROR: v8::ToLocalChecked Empty MaybeLocal." - How to fail a constructor?

Basically I want to check the arguments passed to the constructor and throw an exception when arguments do not meet certain condition.

My C++ Object inherits node::ObjectWrap.

  v8::Persistent<v8::Function> SomeKlass::constructor;

FunctionTemplate is used to set up the constructor in JavaScript.

  void SomeKlass::Init(v8::Local<v8::Object> exports) {

    v8::Isolate* isolate = exports->GetIsolate();

    v8::Local<v8::FunctionTemplate> tpl = v8::FunctionTemplate::New(isolate, New);

    /* ... */

    constructor.Reset(isolate, tpl->GetFunction());

    exports->Set(v8::String::NewFromUtf8(isolate, "SomeKlass"), tpl->GetFunction());

  }

Throwing Exceptions when New is a construct call produces a runtime Fatal Error.

However, throwing the same exception in a 'function call' (without new keyward) works normally.

  void SomeKlass::New(const v8::FunctionCallbackInfo<v8::Value>& args) {

    v8::Isolate *isolate = args.GetIsolate();

    if (args.IsConstructCall()) {

      SomeKlass* obj = new SomeKlass();

      if (...) {
        // set args.This() to undefined.

        /* THIS CAUSES "FATAL ERROR: v8::ToLocalChecked Empty MaybeLocal."
         *
         * isolate->ThrowException(v8::Exception::TypeError(
         *   v8::String::NewFromUtf8(isolate, "Error"))); 
         */

        return;
      }

      obj->Wrap(args.This());

      args.GetReturnValue().Set(args.This());

    } else {

      /* Exceptions do not produce a FATAL ERROR here. */

    }

  }

}

What is the correct way to fail the constructor?

Node version: 6.10.3 or 8.1.4

v8 version: 5.1.281 or 5.8.282

Upvotes: 3

Views: 1749

Answers (1)

Ryanzyy
Ryanzyy

Reputation: 101

I found out why throwing exceptions in constructor causes crash.

It is because I'm calling NewObject in another place.

template <typename T>//;
static v8::Local<v8::Object> NewObject(const T &args) {
  auto isolate = args.GetIsolate();

  auto context = isolate->GetCurrentContext();
  auto cons = v8::Local<v8::Function>::New(isolate, Klass::constructor);
  return cons->NewInstance(context).ToLocalChecked();
}

The failing constructor produces an empty object.

Calling ToLocalChecked() from it causes "FATAL ERROR: v8::ToLocalChecked Empty MaybeLocal.", which is expected and makes sense.

Upvotes: 1

Related Questions