[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:
Philip Jägenstedt 2018-01-24 22:02:00 +07:00 committed by Commit Bot
parent 6d36bae42c
commit ff05633408
2 changed files with 7 additions and 262 deletions

View File

@ -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);

View File

@ -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.