3

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

Ryanzyy
  • 101
  • 1
  • 8
  • What is "set args.This() to undefined" exactly? `args.This()` does not return a reference to be set. – user7860670 Jul 16 '17 at 18:51
  • args.This()->SetAlignedPointerInInternalField(0, nullptr); Not sure if it's the correct way to to this. – Ryanzyy Jul 16 '17 at 18:58
  • And what are you trying to achieve by this? Have you tried throwing exception without calling `SetAlignedPointerInInternalField`? – user7860670 Jul 16 '17 at 19:08
  • Actually I think the error is caused by leaking `SomeKlass` instance. You should move it's creation after throwing block. – user7860670 Jul 16 '17 at 19:44

1 Answers1

1

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.

Ryanzyy
  • 101
  • 1
  • 8