[api] Don't mark as constructible if instance_call_handler is used
This only affects document.all, which is the only user of |ObjectTemplate::SetCallAsFunctionHandler|, and will mean that new document.all() will throw TypeError. There are tests for this: //src/third_party/WebKit/LayoutTests/external/wpt/html/infrastructure/common-dom-interfaces/collections/htmlallcollection.html (cherry picked from commit 7233447e4ac4587c81e91077857f8a30c4a6d2df) Change-Id: Ibb39b3c61b688591c781158cf4abc0c2d74c908e Reviewed-on: https://chromium-review.googlesource.com/882642 Reviewed-by: Adam Klein <adamk@chromium.org> Commit-Queue: Philip Jägenstedt <foolip@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/890496 Cr-Commit-Position: refs/heads/master@{#50943}
This commit is contained in:
parent
6d36bae42c
commit
ff05633408
@ -726,7 +726,6 @@ Handle<JSFunction> ApiNatives::CreateApiFunction(
|
||||
// Mark instance as callable in the map.
|
||||
if (!obj->instance_call_handler()->IsUndefined(isolate)) {
|
||||
map->set_is_callable(true);
|
||||
map->set_is_constructor(true);
|
||||
}
|
||||
|
||||
if (immutable_proto) map->set_is_immutable_proto(true);
|
||||
|
@ -11030,264 +11030,6 @@ THREADED_TEST(Constructor) {
|
||||
}
|
||||
|
||||
|
||||
static void ConstructorCallback(
|
||||
const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
ApiTestFuzzer::Fuzz();
|
||||
Local<Object> This;
|
||||
|
||||
v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
|
||||
if (args.IsConstructCall()) {
|
||||
Local<Object> Holder = args.Holder();
|
||||
This = Object::New(args.GetIsolate());
|
||||
Local<Value> proto = Holder->GetPrototype();
|
||||
if (proto->IsObject()) {
|
||||
This->SetPrototype(context, proto).FromJust();
|
||||
}
|
||||
} else {
|
||||
This = args.This();
|
||||
}
|
||||
|
||||
This->Set(context, v8_str("a"), args[0]).FromJust();
|
||||
args.GetReturnValue().Set(This);
|
||||
}
|
||||
|
||||
|
||||
static void FakeConstructorCallback(
|
||||
const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
ApiTestFuzzer::Fuzz();
|
||||
args.GetReturnValue().Set(args[0]);
|
||||
}
|
||||
|
||||
|
||||
THREADED_TEST(ConstructorForObject) {
|
||||
LocalContext context;
|
||||
v8::Isolate* isolate = context->GetIsolate();
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
|
||||
{
|
||||
Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
|
||||
instance_template->SetCallAsFunctionHandler(ConstructorCallback);
|
||||
Local<Object> instance =
|
||||
instance_template->NewInstance(context.local()).ToLocalChecked();
|
||||
CHECK(context->Global()
|
||||
->Set(context.local(), v8_str("obj"), instance)
|
||||
.FromJust());
|
||||
v8::TryCatch try_catch(isolate);
|
||||
Local<Value> value;
|
||||
CHECK(!try_catch.HasCaught());
|
||||
|
||||
// Call the Object's constructor with a 32-bit signed integer.
|
||||
value = CompileRun("(function() { var o = new obj(28); return o.a; })()");
|
||||
CHECK(!try_catch.HasCaught());
|
||||
CHECK(value->IsInt32());
|
||||
CHECK_EQ(28, value->Int32Value(context.local()).FromJust());
|
||||
|
||||
Local<Value> args1[] = {v8_num(28)};
|
||||
Local<Value> value_obj1 =
|
||||
instance->CallAsConstructor(context.local(), 1, args1).ToLocalChecked();
|
||||
CHECK(value_obj1->IsObject());
|
||||
Local<Object> object1 = Local<Object>::Cast(value_obj1);
|
||||
value = object1->Get(context.local(), v8_str("a")).ToLocalChecked();
|
||||
CHECK(value->IsInt32());
|
||||
CHECK(!try_catch.HasCaught());
|
||||
CHECK_EQ(28, value->Int32Value(context.local()).FromJust());
|
||||
|
||||
// Call the Object's constructor with a String.
|
||||
value =
|
||||
CompileRun("(function() { var o = new obj('tipli'); return o.a; })()");
|
||||
CHECK(!try_catch.HasCaught());
|
||||
CHECK(value->IsString());
|
||||
String::Utf8Value string_value1(
|
||||
isolate, value->ToString(context.local()).ToLocalChecked());
|
||||
CHECK_EQ(0, strcmp("tipli", *string_value1));
|
||||
|
||||
Local<Value> args2[] = {v8_str("tipli")};
|
||||
Local<Value> value_obj2 =
|
||||
instance->CallAsConstructor(context.local(), 1, args2).ToLocalChecked();
|
||||
CHECK(value_obj2->IsObject());
|
||||
Local<Object> object2 = Local<Object>::Cast(value_obj2);
|
||||
value = object2->Get(context.local(), v8_str("a")).ToLocalChecked();
|
||||
CHECK(!try_catch.HasCaught());
|
||||
CHECK(value->IsString());
|
||||
String::Utf8Value string_value2(
|
||||
isolate, value->ToString(context.local()).ToLocalChecked());
|
||||
CHECK_EQ(0, strcmp("tipli", *string_value2));
|
||||
|
||||
// Call the Object's constructor with a Boolean.
|
||||
value = CompileRun("(function() { var o = new obj(true); return o.a; })()");
|
||||
CHECK(!try_catch.HasCaught());
|
||||
CHECK(value->IsBoolean());
|
||||
CHECK(value->BooleanValue(context.local()).FromJust());
|
||||
|
||||
Local<Value> args3[] = {v8::True(isolate)};
|
||||
Local<Value> value_obj3 =
|
||||
instance->CallAsConstructor(context.local(), 1, args3).ToLocalChecked();
|
||||
CHECK(value_obj3->IsObject());
|
||||
Local<Object> object3 = Local<Object>::Cast(value_obj3);
|
||||
value = object3->Get(context.local(), v8_str("a")).ToLocalChecked();
|
||||
CHECK(!try_catch.HasCaught());
|
||||
CHECK(value->IsBoolean());
|
||||
CHECK(value->BooleanValue(context.local()).FromJust());
|
||||
|
||||
// Call the Object's constructor with undefined.
|
||||
Local<Value> args4[] = {v8::Undefined(isolate)};
|
||||
Local<Value> value_obj4 =
|
||||
instance->CallAsConstructor(context.local(), 1, args4).ToLocalChecked();
|
||||
CHECK(value_obj4->IsObject());
|
||||
Local<Object> object4 = Local<Object>::Cast(value_obj4);
|
||||
value = object4->Get(context.local(), v8_str("a")).ToLocalChecked();
|
||||
CHECK(!try_catch.HasCaught());
|
||||
CHECK(value->IsUndefined());
|
||||
|
||||
// Call the Object's constructor with null.
|
||||
Local<Value> args5[] = {v8::Null(isolate)};
|
||||
Local<Value> value_obj5 =
|
||||
instance->CallAsConstructor(context.local(), 1, args5).ToLocalChecked();
|
||||
CHECK(value_obj5->IsObject());
|
||||
Local<Object> object5 = Local<Object>::Cast(value_obj5);
|
||||
value = object5->Get(context.local(), v8_str("a")).ToLocalChecked();
|
||||
CHECK(!try_catch.HasCaught());
|
||||
CHECK(value->IsNull());
|
||||
}
|
||||
|
||||
// Check exception handling when there is no constructor set for the Object.
|
||||
{
|
||||
Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
|
||||
Local<Object> instance =
|
||||
instance_template->NewInstance(context.local()).ToLocalChecked();
|
||||
CHECK(context->Global()
|
||||
->Set(context.local(), v8_str("obj2"), instance)
|
||||
.FromJust());
|
||||
v8::TryCatch try_catch(isolate);
|
||||
Local<Value> value;
|
||||
CHECK(!try_catch.HasCaught());
|
||||
|
||||
value = CompileRun("new obj2(28)");
|
||||
CHECK(try_catch.HasCaught());
|
||||
String::Utf8Value exception_value1(isolate, try_catch.Exception());
|
||||
CHECK_EQ(0,
|
||||
strcmp("TypeError: obj2 is not a constructor", *exception_value1));
|
||||
try_catch.Reset();
|
||||
|
||||
Local<Value> args[] = {v8_num(29)};
|
||||
CHECK(instance->CallAsConstructor(context.local(), 1, args).IsEmpty());
|
||||
CHECK(try_catch.HasCaught());
|
||||
String::Utf8Value exception_value2(isolate, try_catch.Exception());
|
||||
CHECK_EQ(
|
||||
0, strcmp("TypeError: object is not a constructor", *exception_value2));
|
||||
try_catch.Reset();
|
||||
}
|
||||
|
||||
// Check the case when constructor throws exception.
|
||||
{
|
||||
Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
|
||||
instance_template->SetCallAsFunctionHandler(ThrowValue);
|
||||
Local<Object> instance =
|
||||
instance_template->NewInstance(context.local()).ToLocalChecked();
|
||||
CHECK(context->Global()
|
||||
->Set(context.local(), v8_str("obj3"), instance)
|
||||
.FromJust());
|
||||
v8::TryCatch try_catch(isolate);
|
||||
Local<Value> value;
|
||||
CHECK(!try_catch.HasCaught());
|
||||
|
||||
value = CompileRun("new obj3(22)");
|
||||
CHECK(try_catch.HasCaught());
|
||||
String::Utf8Value exception_value1(isolate, try_catch.Exception());
|
||||
CHECK_EQ(0, strcmp("22", *exception_value1));
|
||||
try_catch.Reset();
|
||||
|
||||
Local<Value> args[] = {v8_num(23)};
|
||||
CHECK(instance->CallAsConstructor(context.local(), 1, args).IsEmpty());
|
||||
CHECK(try_catch.HasCaught());
|
||||
String::Utf8Value exception_value2(isolate, try_catch.Exception());
|
||||
CHECK_EQ(0, strcmp("23", *exception_value2));
|
||||
try_catch.Reset();
|
||||
}
|
||||
|
||||
// Check whether constructor returns with an object or non-object.
|
||||
{
|
||||
Local<FunctionTemplate> function_template =
|
||||
FunctionTemplate::New(isolate, FakeConstructorCallback);
|
||||
Local<Function> function =
|
||||
function_template->GetFunction(context.local()).ToLocalChecked();
|
||||
Local<Object> instance1 = function;
|
||||
CHECK(instance1->IsObject());
|
||||
CHECK(instance1->IsFunction());
|
||||
CHECK(context->Global()
|
||||
->Set(context.local(), v8_str("obj4"), instance1)
|
||||
.FromJust());
|
||||
v8::TryCatch try_catch(isolate);
|
||||
CHECK(!try_catch.HasCaught());
|
||||
|
||||
{
|
||||
Local<Value> value = CompileRun("new obj4(28)");
|
||||
CHECK(!try_catch.HasCaught());
|
||||
CHECK(value->IsObject());
|
||||
|
||||
Local<Value> args[] = {v8_num(28)};
|
||||
value = instance1->CallAsConstructor(context.local(), 1, args)
|
||||
.ToLocalChecked();
|
||||
CHECK(!try_catch.HasCaught());
|
||||
CHECK(value->IsObject());
|
||||
}
|
||||
|
||||
Local<Value> proxy = CompileRun("proxy = new Proxy({},{})");
|
||||
CHECK(!try_catch.HasCaught());
|
||||
CHECK(proxy->IsProxy());
|
||||
|
||||
{
|
||||
Local<Value> value = CompileRun("new obj4(proxy)");
|
||||
CHECK(!try_catch.HasCaught());
|
||||
CHECK(value->IsProxy());
|
||||
CHECK(value->SameValue(proxy));
|
||||
|
||||
Local<Value> args[] = {proxy};
|
||||
value = instance1->CallAsConstructor(context.local(), 1, args)
|
||||
.ToLocalChecked();
|
||||
CHECK(!try_catch.HasCaught());
|
||||
CHECK(value->SameValue(proxy));
|
||||
}
|
||||
|
||||
Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
|
||||
instance_template->SetCallAsFunctionHandler(FakeConstructorCallback);
|
||||
Local<Object> instance2 =
|
||||
instance_template->NewInstance(context.local()).ToLocalChecked();
|
||||
CHECK(instance2->IsObject());
|
||||
CHECK(instance2->IsFunction());
|
||||
CHECK(context->Global()
|
||||
->Set(context.local(), v8_str("obj5"), instance2)
|
||||
.FromJust());
|
||||
CHECK(!try_catch.HasCaught());
|
||||
|
||||
{
|
||||
Local<Value> value = CompileRun("new obj5(28)");
|
||||
CHECK(!try_catch.HasCaught());
|
||||
CHECK(!value->IsObject());
|
||||
|
||||
Local<Value> args[] = {v8_num(28)};
|
||||
value = instance2->CallAsConstructor(context.local(), 1, args)
|
||||
.ToLocalChecked();
|
||||
CHECK(!try_catch.HasCaught());
|
||||
CHECK(!value->IsObject());
|
||||
}
|
||||
|
||||
{
|
||||
Local<Value> value = CompileRun("new obj5(proxy)");
|
||||
CHECK(!try_catch.HasCaught());
|
||||
CHECK(value->IsProxy());
|
||||
CHECK(value->SameValue(proxy));
|
||||
|
||||
Local<Value> args[] = {proxy};
|
||||
value = instance2->CallAsConstructor(context.local(), 1, args)
|
||||
.ToLocalChecked();
|
||||
CHECK(!try_catch.HasCaught());
|
||||
CHECK(value->SameValue(proxy));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
THREADED_TEST(FunctionDescriptorException) {
|
||||
LocalContext context;
|
||||
v8::Isolate* isolate = context->GetIsolate();
|
||||
@ -11583,11 +11325,15 @@ THREADED_TEST(CallAsFunction) {
|
||||
CHECK(!try_catch.HasCaught());
|
||||
CHECK_EQ(17, value->Int32Value(context.local()).FromJust());
|
||||
|
||||
// Check that the call-as-function handler can be called through
|
||||
// Check that the call-as-function handler cannot be called through
|
||||
// new.
|
||||
value = CompileRun("new obj(43)");
|
||||
CHECK(!try_catch.HasCaught());
|
||||
CHECK_EQ(-43, value->Int32Value(context.local()).FromJust());
|
||||
CHECK(value.IsEmpty());
|
||||
CHECK(try_catch.HasCaught());
|
||||
String::Utf8Value exception_value(isolate, try_catch.Exception());
|
||||
CHECK_EQ(0,
|
||||
strcmp("TypeError: obj is not a constructor", *exception_value));
|
||||
try_catch.Reset();
|
||||
|
||||
// Check that the call-as-function handler can be called through
|
||||
// the API.
|
||||
|
Loading…
Reference in New Issue
Block a user