From 105f6062024fd5c5604d1d5253a72c53b1f5c529 Mon Sep 17 00:00:00 2001 From: Gus Caplan Date: Mon, 7 May 2018 08:36:43 -0500 Subject: [PATCH] v8: backport 9fb02b526f1cd3b859a530a01adb08bc0d089f4f Refs: https://github.com/v8/v8/commit/9fb02b526f1cd3b859a530a01adb08bc0d089f4f Original commit message: Allow function callbacks to have Proxy as receiver. R=verwaest@chromium.org Bug: v8:5773 Change-Id: Ifd29a1116ee8c86b8d8d24485bbfd19e260ab66b Reviewed-on: chromium-review.googlesource.com/1046088 Commit-Queue: Yang Guo Reviewed-by: Camillo Bruni Cr-Commit-Position: refs/heads/master@{#53015} PR-URL: https://github.com/nodejs/node/pull/20575 Reviewed-By: James M Snell Reviewed-By: Ben Noordhuis --- common.gypi | 2 +- deps/v8/src/builtins/builtins-api.cc | 41 ++++++++++++++-------------- deps/v8/test/cctest/test-api.cc | 28 +++++++++++++++++++ 3 files changed, 50 insertions(+), 21 deletions(-) diff --git a/common.gypi b/common.gypi index 3bb10d611fb1d5..adeaf85c12bac1 100644 --- a/common.gypi +++ b/common.gypi @@ -27,7 +27,7 @@ # Reset this number to 0 on major V8 upgrades. # Increment by one for each non-official patch applied to deps/v8. - 'v8_embedder_string': '-node.6', + 'v8_embedder_string': '-node.7', # Enable disassembler for `--print-code` v8 options 'v8_enable_disassembler': 1, diff --git a/deps/v8/src/builtins/builtins-api.cc b/deps/v8/src/builtins/builtins-api.cc index 971fb7c678499f..bb66b082f3edf3 100644 --- a/deps/v8/src/builtins/builtins-api.cc +++ b/deps/v8/src/builtins/builtins-api.cc @@ -21,17 +21,21 @@ namespace { // Returns the holder JSObject if the function can legally be called with this // receiver. Returns nullptr if the call is illegal. // TODO(dcarney): CallOptimization duplicates this logic, merge. -JSObject* GetCompatibleReceiver(Isolate* isolate, FunctionTemplateInfo* info, - JSObject* receiver) { +JSReceiver* GetCompatibleReceiver(Isolate* isolate, FunctionTemplateInfo* info, + JSReceiver* receiver) { Object* recv_type = info->signature(); // No signature, return holder. if (!recv_type->IsFunctionTemplateInfo()) return receiver; + // A Proxy cannot have been created from the signature template. + if (!receiver->IsJSObject()) return nullptr; + + JSObject* js_obj_receiver = JSObject::cast(receiver); FunctionTemplateInfo* signature = FunctionTemplateInfo::cast(recv_type); // Check the receiver. Fast path for receivers with no hidden prototypes. - if (signature->IsTemplateFor(receiver)) return receiver; - if (!receiver->map()->has_hidden_prototype()) return nullptr; - for (PrototypeIterator iter(isolate, receiver, kStartAtPrototype, + if (signature->IsTemplateFor(js_obj_receiver)) return receiver; + if (!js_obj_receiver->map()->has_hidden_prototype()) return nullptr; + for (PrototypeIterator iter(isolate, js_obj_receiver, kStartAtPrototype, PrototypeIterator::END_AT_NON_HIDDEN); !iter.IsAtEnd(); iter.Advance()) { JSObject* current = iter.GetCurrent(); @@ -45,8 +49,8 @@ MUST_USE_RESULT MaybeHandle HandleApiCallHelper( Isolate* isolate, Handle function, Handle new_target, Handle fun_data, Handle receiver, BuiltinArguments args) { - Handle js_receiver; - JSObject* raw_holder; + Handle js_receiver; + JSReceiver* raw_holder; if (is_construct) { DCHECK(args.receiver()->IsTheHole(isolate)); if (fun_data->instance_template()->IsUndefined(isolate)) { @@ -68,21 +72,18 @@ MUST_USE_RESULT MaybeHandle HandleApiCallHelper( raw_holder = *js_receiver; } else { DCHECK(receiver->IsJSReceiver()); - - if (!receiver->IsJSObject()) { - // This function cannot be called with the given receiver. Abort! - THROW_NEW_ERROR( - isolate, NewTypeError(MessageTemplate::kIllegalInvocation), Object); - } - - js_receiver = Handle::cast(receiver); + js_receiver = Handle::cast(receiver); if (!fun_data->accept_any_receiver() && - js_receiver->IsAccessCheckNeeded() && - !isolate->MayAccess(handle(isolate->context()), js_receiver)) { - isolate->ReportFailedAccessCheck(js_receiver); - RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); - return isolate->factory()->undefined_value(); + js_receiver->IsAccessCheckNeeded()) { + // Proxies never need access checks. + DCHECK(js_receiver->IsJSObject()); + Handle js_obj_receiver = Handle::cast(js_receiver); + if (!isolate->MayAccess(handle(isolate->context()), js_obj_receiver)) { + isolate->ReportFailedAccessCheck(js_obj_receiver); + RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); + return isolate->factory()->undefined_value(); + } } raw_holder = GetCompatibleReceiver(isolate, *fun_data, *js_receiver); diff --git a/deps/v8/test/cctest/test-api.cc b/deps/v8/test/cctest/test-api.cc index fe1aca5a0fb440..40ba60ffb36607 100644 --- a/deps/v8/test/cctest/test-api.cc +++ b/deps/v8/test/cctest/test-api.cc @@ -1088,6 +1088,34 @@ THREADED_PROFILED_TEST(FunctionTemplate) { TestFunctionTemplateAccessor(construct_callback, Return239Callback); } +static void FunctionCallbackForProxyTest( + const v8::FunctionCallbackInfo& info) { + info.GetReturnValue().Set(info.This()); +} + +THREADED_TEST(FunctionTemplateWithProxy) { + LocalContext env; + v8::Isolate* isolate = env->GetIsolate(); + v8::HandleScope scope(isolate); + + v8::Local function_template = + v8::FunctionTemplate::New(isolate, FunctionCallbackForProxyTest); + v8::Local function = + function_template->GetFunction(env.local()).ToLocalChecked(); + CHECK((*env)->Global()->Set(env.local(), v8_str("f"), function).FromJust()); + v8::Local proxy = + CompileRun("var proxy = new Proxy({}, {}); proxy"); + CHECK(proxy->IsProxy()); + + v8::Local result = CompileRun("f(proxy)"); + CHECK(result->Equals(env.local(), (*env)->Global()).FromJust()); + + result = CompileRun("f.call(proxy)"); + CHECK(result->Equals(env.local(), proxy).FromJust()); + + result = CompileRun("Reflect.apply(f, proxy, [1])"); + CHECK(result->Equals(env.local(), proxy).FromJust()); +} static void SimpleCallback(const v8::FunctionCallbackInfo& info) { ApiTestFuzzer::Fuzz();