Commit 8e18ea39 authored by legendecas's avatar legendecas Committed by V8 LUCI CQ

[builtins] Fix binding function with native data property accessors

When the function is created with FunctionTemplate and set name with
native data property accessors, binding the function should throw
immediately if the native accessor throws.

Bug: v8:11989
Change-Id: Ief282202aa5b8515f581fd5478886ed5f001fd4f
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3492966Reviewed-by: 's avatarShu-yu Guo <syg@chromium.org>
Commit-Queue: Chengzhong Wu <legendecas@gmail.com>
Cr-Commit-Position: refs/heads/main@{#79356}
parent a0b25ebd
......@@ -207,16 +207,18 @@ Object DoFunctionBind(Isolate* isolate, BuiltinArguments args) {
isolate, function,
isolate->factory()->NewJSBoundFunction(target, this_arg, argv));
LookupIterator length_lookup(isolate, target,
isolate->factory()->length_string(), target,
LookupIterator::OWN);
// Setup the "length" property based on the "length" of the {target}.
// If the targets length is the default JSFunction accessor, we can keep the
// accessor that's installed by default on the JSBoundFunction. It lazily
// computes the value from the underlying internal length.
Handle<AccessorInfo> function_length_accessor =
isolate->factory()->function_length_accessor();
LookupIterator length_lookup(isolate, target,
isolate->factory()->length_string(), target,
LookupIterator::OWN);
if (!target->IsJSFunction() ||
length_lookup.state() != LookupIterator::ACCESSOR ||
!length_lookup.GetAccessors()->IsAccessorInfo()) {
!length_lookup.GetAccessors().is_identical_to(function_length_accessor)) {
Handle<Object> length(Smi::zero(), isolate);
Maybe<PropertyAttributes> attributes =
JSReceiver::GetPropertyAttributes(&length_lookup);
......@@ -242,11 +244,13 @@ Object DoFunctionBind(Isolate* isolate, BuiltinArguments args) {
// If the target's name is the default JSFunction accessor, we can keep the
// accessor that's installed by default on the JSBoundFunction. It lazily
// computes the value from the underlying internal name.
Handle<AccessorInfo> function_name_accessor =
isolate->factory()->function_name_accessor();
LookupIterator name_lookup(isolate, target, isolate->factory()->name_string(),
target);
if (!target->IsJSFunction() ||
name_lookup.state() != LookupIterator::ACCESSOR ||
!name_lookup.GetAccessors()->IsAccessorInfo() ||
!name_lookup.GetAccessors().is_identical_to(function_name_accessor) ||
(name_lookup.IsFound() && !name_lookup.HolderIsReceiver())) {
Handle<Object> target_name;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, target_name,
......@@ -257,8 +261,9 @@ Object DoFunctionBind(Isolate* isolate, BuiltinArguments args) {
isolate, name,
Name::ToFunctionName(isolate, Handle<String>::cast(target_name)));
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, name, isolate->factory()->NewConsString(
isolate->factory()->bound__string(), name));
isolate, name,
isolate->factory()->NewConsString(isolate->factory()->bound__string(),
name));
} else {
name = isolate->factory()->bound__string();
}
......
......@@ -778,3 +778,42 @@ TEST(ObjectTemplateSetLazyPropertyHasNoSideEffect) {
->Int32Value(env.local())
.FromJust());
}
namespace {
void FunctionNativeGetter(v8::Local<v8::String> property,
const v8::PropertyCallbackInfo<v8::Value>& info) {
info.GetIsolate()->ThrowError(v8_str("side effect in getter"));
}
} // namespace
TEST(BindFunctionTemplateSetNativeDataProperty) {
LocalContext env;
v8::Isolate* isolate = env->GetIsolate();
v8::HandleScope scope(isolate);
// Check that getter is called on Function.prototype.bind.
{
v8::Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
templ->SetNativeDataProperty(v8_str("name"), FunctionNativeGetter);
v8::Local<v8::Function> func =
templ->GetFunction(env.local()).ToLocalChecked();
CHECK(env->Global()->Set(env.local(), v8_str("func"), func).FromJust());
v8::TryCatch try_catch(isolate);
CHECK(CompileRun("func.bind()").IsEmpty());
CHECK(try_catch.HasCaught());
}
// Check that getter is called on Function.prototype.bind.
{
v8::Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
templ->SetNativeDataProperty(v8_str("length"), FunctionNativeGetter);
v8::Local<v8::Function> func =
templ->GetFunction(env.local()).ToLocalChecked();
CHECK(env->Global()->Set(env.local(), v8_str("func"), func).FromJust());
v8::TryCatch try_catch(isolate);
CHECK(CompileRun("func.bind()").IsEmpty());
CHECK(try_catch.HasCaught());
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment