|
@@ -0,0 +1,358 @@
|
|
|
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
|
+From: Igor Sheludko <[email protected]>
|
|
|
+Date: Thu, 27 Apr 2023 11:11:32 +0200
|
|
|
+Subject: Fix v8::Object::SetAccessorProperty
|
|
|
+
|
|
|
+... by using JavaScript spec compliant JSReceiver::DefineOwnProperty.
|
|
|
+
|
|
|
+Drive-by:
|
|
|
+- cleanup comments in include/v8-object.h, insert links to
|
|
|
+respective pages of https://tc39.es/ecma262/ when referencing spec,
|
|
|
+- rename JSObject::DefineAccessor() to
|
|
|
+ JSObject::DefineOwnAccessorIgnoreAttributes().
|
|
|
+
|
|
|
+Bug: chromium:1433211
|
|
|
+Change-Id: Ia9edaadd68f1986f18581156ad8f79c438b77744
|
|
|
+Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4458947
|
|
|
+Commit-Queue: Igor Sheludko <[email protected]>
|
|
|
+Reviewed-by: Toon Verwaest <[email protected]>
|
|
|
+Cr-Commit-Position: refs/heads/main@{#87302}
|
|
|
+
|
|
|
+diff --git a/include/v8-object.h b/include/v8-object.h
|
|
|
+index 6c03d63c482c4096777b887d6f6a22336f82147e..6954c00b50a504d2a0205fb67f314e4e50fb455a 100644
|
|
|
+--- a/include/v8-object.h
|
|
|
++++ b/include/v8-object.h
|
|
|
+@@ -247,13 +247,16 @@ class V8_EXPORT Object : public Value {
|
|
|
+ V8_WARN_UNUSED_RESULT Maybe<bool> Set(Local<Context> context, uint32_t index,
|
|
|
+ Local<Value> value);
|
|
|
+
|
|
|
+- // Implements CreateDataProperty (ECMA-262, 7.3.4).
|
|
|
+- //
|
|
|
+- // Defines a configurable, writable, enumerable property with the given value
|
|
|
+- // on the object unless the property already exists and is not configurable
|
|
|
+- // or the object is not extensible.
|
|
|
+- //
|
|
|
+- // Returns true on success.
|
|
|
++ /**
|
|
|
++ * Implements CreateDataProperty(O, P, V), see
|
|
|
++ * https://tc39.es/ecma262/#sec-createdataproperty.
|
|
|
++ *
|
|
|
++ * Defines a configurable, writable, enumerable property with the given value
|
|
|
++ * on the object unless the property already exists and is not configurable
|
|
|
++ * or the object is not extensible.
|
|
|
++ *
|
|
|
++ * Returns true on success.
|
|
|
++ */
|
|
|
+ V8_WARN_UNUSED_RESULT Maybe<bool> CreateDataProperty(Local<Context> context,
|
|
|
+ Local<Name> key,
|
|
|
+ Local<Value> value);
|
|
|
+@@ -261,29 +264,35 @@ class V8_EXPORT Object : public Value {
|
|
|
+ uint32_t index,
|
|
|
+ Local<Value> value);
|
|
|
+
|
|
|
+- // Implements DefineOwnProperty.
|
|
|
+- //
|
|
|
+- // In general, CreateDataProperty will be faster, however, does not allow
|
|
|
+- // for specifying attributes.
|
|
|
+- //
|
|
|
+- // Returns true on success.
|
|
|
++ /**
|
|
|
++ * Implements [[DefineOwnProperty]] for data property case, see
|
|
|
++ * https://tc39.es/ecma262/#table-essential-internal-methods.
|
|
|
++ *
|
|
|
++ * In general, CreateDataProperty will be faster, however, does not allow
|
|
|
++ * for specifying attributes.
|
|
|
++ *
|
|
|
++ * Returns true on success.
|
|
|
++ */
|
|
|
+ V8_WARN_UNUSED_RESULT Maybe<bool> DefineOwnProperty(
|
|
|
+ Local<Context> context, Local<Name> key, Local<Value> value,
|
|
|
+ PropertyAttribute attributes = None);
|
|
|
+
|
|
|
+- // Implements Object.DefineProperty(O, P, Attributes), see Ecma-262 19.1.2.4.
|
|
|
+- //
|
|
|
+- // The defineProperty function is used to add an own property or
|
|
|
+- // update the attributes of an existing own property of an object.
|
|
|
+- //
|
|
|
+- // Both data and accessor descriptors can be used.
|
|
|
+- //
|
|
|
+- // In general, CreateDataProperty is faster, however, does not allow
|
|
|
+- // for specifying attributes or an accessor descriptor.
|
|
|
+- //
|
|
|
+- // The PropertyDescriptor can change when redefining a property.
|
|
|
+- //
|
|
|
+- // Returns true on success.
|
|
|
++ /**
|
|
|
++ * Implements Object.defineProperty(O, P, Attributes), see
|
|
|
++ * https://tc39.es/ecma262/#sec-object.defineproperty.
|
|
|
++ *
|
|
|
++ * The defineProperty function is used to add an own property or
|
|
|
++ * update the attributes of an existing own property of an object.
|
|
|
++ *
|
|
|
++ * Both data and accessor descriptors can be used.
|
|
|
++ *
|
|
|
++ * In general, CreateDataProperty is faster, however, does not allow
|
|
|
++ * for specifying attributes or an accessor descriptor.
|
|
|
++ *
|
|
|
++ * The PropertyDescriptor can change when redefining a property.
|
|
|
++ *
|
|
|
++ * Returns true on success.
|
|
|
++ */
|
|
|
+ V8_WARN_UNUSED_RESULT Maybe<bool> DefineProperty(
|
|
|
+ Local<Context> context, Local<Name> key, PropertyDescriptor& descriptor);
|
|
|
+
|
|
|
+@@ -302,14 +311,15 @@ class V8_EXPORT Object : public Value {
|
|
|
+ Local<Context> context, Local<Value> key);
|
|
|
+
|
|
|
+ /**
|
|
|
+- * Returns Object.getOwnPropertyDescriptor as per ES2016 section 19.1.2.6.
|
|
|
++ * Implements Object.getOwnPropertyDescriptor(O, P), see
|
|
|
++ * https://tc39.es/ecma262/#sec-object.getownpropertydescriptor.
|
|
|
+ */
|
|
|
+ V8_WARN_UNUSED_RESULT MaybeLocal<Value> GetOwnPropertyDescriptor(
|
|
|
+ Local<Context> context, Local<Name> key);
|
|
|
+
|
|
|
+ /**
|
|
|
+- * Object::Has() calls the abstract operation HasProperty(O, P) described
|
|
|
+- * in ECMA-262, 7.3.10. Has() returns
|
|
|
++ * Object::Has() calls the abstract operation HasProperty(O, P), see
|
|
|
++ * https://tc39.es/ecma262/#sec-hasproperty. Has() returns
|
|
|
+ * true, if the object has the property, either own or on the prototype chain.
|
|
|
+ * Interceptors, i.e., PropertyQueryCallbacks, are called if present.
|
|
|
+ *
|
|
|
+@@ -347,7 +357,7 @@ class V8_EXPORT Object : public Value {
|
|
|
+
|
|
|
+ void SetAccessorProperty(Local<Name> name, Local<Function> getter,
|
|
|
+ Local<Function> setter = Local<Function>(),
|
|
|
+- PropertyAttribute attribute = None,
|
|
|
++ PropertyAttribute attributes = None,
|
|
|
+ AccessControl settings = DEFAULT);
|
|
|
+
|
|
|
+ /**
|
|
|
+diff --git a/src/api/api-natives.cc b/src/api/api-natives.cc
|
|
|
+index 05a883f2d560e360b6933639dab3ec956464cb1a..905f29bf253c443204f3f9f36fd4c948ed434f15 100644
|
|
|
+--- a/src/api/api-natives.cc
|
|
|
++++ b/src/api/api-natives.cc
|
|
|
+@@ -96,10 +96,10 @@ MaybeHandle<Object> DefineAccessorProperty(Isolate* isolate,
|
|
|
+ Handle<Code> trampoline = BUILTIN_CODE(isolate, DebugBreakTrampoline);
|
|
|
+ Handle<JSFunction>::cast(setter)->set_code(*trampoline);
|
|
|
+ }
|
|
|
+- RETURN_ON_EXCEPTION(
|
|
|
+- isolate,
|
|
|
+- JSObject::DefineAccessor(object, name, getter, setter, attributes),
|
|
|
+- Object);
|
|
|
++ RETURN_ON_EXCEPTION(isolate,
|
|
|
++ JSObject::DefineOwnAccessorIgnoreAttributes(
|
|
|
++ object, name, getter, setter, attributes),
|
|
|
++ Object);
|
|
|
+ return object;
|
|
|
+ }
|
|
|
+
|
|
|
+diff --git a/src/api/api.cc b/src/api/api.cc
|
|
|
+index d664893fca9e378853eaaae5b174679dadc75d91..a30c50948ab634313f33d5eb96cef98fa671d121 100644
|
|
|
+--- a/src/api/api.cc
|
|
|
++++ b/src/api/api.cc
|
|
|
+@@ -5138,7 +5138,7 @@ Maybe<bool> Object::SetAccessor(Local<Context> context, Local<Name> name,
|
|
|
+
|
|
|
+ void Object::SetAccessorProperty(Local<Name> name, Local<Function> getter,
|
|
|
+ Local<Function> setter,
|
|
|
+- PropertyAttribute attribute,
|
|
|
++ PropertyAttribute attributes,
|
|
|
+ AccessControl settings) {
|
|
|
+ // TODO(verwaest): Remove |settings|.
|
|
|
+ DCHECK_EQ(v8::DEFAULT, settings);
|
|
|
+@@ -5150,9 +5150,20 @@ void Object::SetAccessorProperty(Local<Name> name, Local<Function> getter,
|
|
|
+ i::Handle<i::Object> getter_i = v8::Utils::OpenHandle(*getter);
|
|
|
+ i::Handle<i::Object> setter_i = v8::Utils::OpenHandle(*setter, true);
|
|
|
+ if (setter_i.is_null()) setter_i = i_isolate->factory()->null_value();
|
|
|
+- i::JSObject::DefineAccessor(i::Handle<i::JSObject>::cast(self),
|
|
|
+- v8::Utils::OpenHandle(*name), getter_i, setter_i,
|
|
|
+- static_cast<i::PropertyAttributes>(attribute));
|
|
|
++
|
|
|
++ i::PropertyDescriptor desc;
|
|
|
++ desc.set_enumerable(!(attributes & v8::DontEnum));
|
|
|
++ desc.set_configurable(!(attributes & v8::DontDelete));
|
|
|
++ desc.set_get(getter_i);
|
|
|
++ desc.set_set(setter_i);
|
|
|
++
|
|
|
++ i::Handle<i::Name> name_i = v8::Utils::OpenHandle(*name);
|
|
|
++ // DefineOwnProperty might still throw if the receiver is a JSProxy and it
|
|
|
++ // might fail if the receiver is non-extensible or already has this property
|
|
|
++ // as non-configurable.
|
|
|
++ Maybe<bool> success = i::JSReceiver::DefineOwnProperty(
|
|
|
++ i_isolate, self, name_i, &desc, Just(i::kDontThrow));
|
|
|
++ USE(success);
|
|
|
+ }
|
|
|
+
|
|
|
+ Maybe<bool> Object::SetNativeDataProperty(
|
|
|
+diff --git a/src/init/bootstrapper.cc b/src/init/bootstrapper.cc
|
|
|
+index 06d945e25356958b206cadc352829ae37610ec16..139acc88ac7efa74182f2c43dacf039c87e08f32 100644
|
|
|
+--- a/src/init/bootstrapper.cc
|
|
|
++++ b/src/init/bootstrapper.cc
|
|
|
+@@ -638,7 +638,9 @@ V8_NOINLINE void SimpleInstallGetterSetter(Isolate* isolate,
|
|
|
+ Handle<JSFunction> setter =
|
|
|
+ SimpleCreateFunction(isolate, setter_name, call_setter, 1, true);
|
|
|
+
|
|
|
+- JSObject::DefineAccessor(base, name, getter, setter, DONT_ENUM).Check();
|
|
|
++ JSObject::DefineOwnAccessorIgnoreAttributes(base, name, getter, setter,
|
|
|
++ DONT_ENUM)
|
|
|
++ .Check();
|
|
|
+ }
|
|
|
+
|
|
|
+ void SimpleInstallGetterSetter(Isolate* isolate, Handle<JSObject> base,
|
|
|
+@@ -662,7 +664,8 @@ V8_NOINLINE Handle<JSFunction> SimpleInstallGetter(Isolate* isolate,
|
|
|
+
|
|
|
+ Handle<Object> setter = isolate->factory()->undefined_value();
|
|
|
+
|
|
|
+- JSObject::DefineAccessor(base, property_name, getter, setter, DONT_ENUM)
|
|
|
++ JSObject::DefineOwnAccessorIgnoreAttributes(base, property_name, getter,
|
|
|
++ setter, DONT_ENUM)
|
|
|
+ .Check();
|
|
|
+
|
|
|
+ return getter;
|
|
|
+diff --git a/src/objects/js-objects.cc b/src/objects/js-objects.cc
|
|
|
+index 8fbf7a135e36085e8a32c8224c35db45702b4ab1..f3a45f1a1220f68a277617617cc0c534d5e542a2 100644
|
|
|
+--- a/src/objects/js-objects.cc
|
|
|
++++ b/src/objects/js-objects.cc
|
|
|
+@@ -1541,7 +1541,8 @@ Maybe<bool> JSReceiver::ValidateAndApplyPropertyDescriptor(
|
|
|
+ ? desc->set()
|
|
|
+ : Handle<Object>::cast(isolate->factory()->null_value()));
|
|
|
+ MaybeHandle<Object> result =
|
|
|
+- JSObject::DefineAccessor(it, getter, setter, desc->ToAttributes());
|
|
|
++ JSObject::DefineOwnAccessorIgnoreAttributes(it, getter, setter,
|
|
|
++ desc->ToAttributes());
|
|
|
+ if (result.is_null()) return Nothing<bool>();
|
|
|
+ }
|
|
|
+ }
|
|
|
+@@ -1725,8 +1726,8 @@ Maybe<bool> JSReceiver::ValidateAndApplyPropertyDescriptor(
|
|
|
+ : current->has_set()
|
|
|
+ ? current->set()
|
|
|
+ : Handle<Object>::cast(isolate->factory()->null_value()));
|
|
|
+- MaybeHandle<Object> result =
|
|
|
+- JSObject::DefineAccessor(it, getter, setter, attrs);
|
|
|
++ MaybeHandle<Object> result = JSObject::DefineOwnAccessorIgnoreAttributes(
|
|
|
++ it, getter, setter, attrs);
|
|
|
+ if (result.is_null()) return Nothing<bool>();
|
|
|
+ }
|
|
|
+ }
|
|
|
+@@ -4703,22 +4704,19 @@ bool JSObject::HasEnumerableElements() {
|
|
|
+ UNREACHABLE();
|
|
|
+ }
|
|
|
+
|
|
|
+-MaybeHandle<Object> JSObject::DefineAccessor(Handle<JSObject> object,
|
|
|
+- Handle<Name> name,
|
|
|
+- Handle<Object> getter,
|
|
|
+- Handle<Object> setter,
|
|
|
+- PropertyAttributes attributes) {
|
|
|
++MaybeHandle<Object> JSObject::DefineOwnAccessorIgnoreAttributes(
|
|
|
++ Handle<JSObject> object, Handle<Name> name, Handle<Object> getter,
|
|
|
++ Handle<Object> setter, PropertyAttributes attributes) {
|
|
|
+ Isolate* isolate = object->GetIsolate();
|
|
|
+
|
|
|
+ PropertyKey key(isolate, name);
|
|
|
+ LookupIterator it(isolate, object, key, LookupIterator::OWN_SKIP_INTERCEPTOR);
|
|
|
+- return DefineAccessor(&it, getter, setter, attributes);
|
|
|
++ return DefineOwnAccessorIgnoreAttributes(&it, getter, setter, attributes);
|
|
|
+ }
|
|
|
+
|
|
|
+-MaybeHandle<Object> JSObject::DefineAccessor(LookupIterator* it,
|
|
|
+- Handle<Object> getter,
|
|
|
+- Handle<Object> setter,
|
|
|
+- PropertyAttributes attributes) {
|
|
|
++MaybeHandle<Object> JSObject::DefineOwnAccessorIgnoreAttributes(
|
|
|
++ LookupIterator* it, Handle<Object> getter, Handle<Object> setter,
|
|
|
++ PropertyAttributes attributes) {
|
|
|
+ Isolate* isolate = it->isolate();
|
|
|
+
|
|
|
+ it->UpdateProtector();
|
|
|
+diff --git a/src/objects/js-objects.h b/src/objects/js-objects.h
|
|
|
+index 80a64a63a16e2aaed7aeacbd734f4488df34e91b..870eb81553f0debadea08a20aad44ff216f09226 100644
|
|
|
+--- a/src/objects/js-objects.h
|
|
|
++++ b/src/objects/js-objects.h
|
|
|
+@@ -538,13 +538,14 @@ class JSObject : public TorqueGeneratedJSObject<JSObject, JSReceiver> {
|
|
|
+ GetPropertyAttributesWithFailedAccessCheck(LookupIterator* it);
|
|
|
+
|
|
|
+ // Defines an AccessorPair property on the given object.
|
|
|
+- V8_EXPORT_PRIVATE static MaybeHandle<Object> DefineAccessor(
|
|
|
+- Handle<JSObject> object, Handle<Name> name, Handle<Object> getter,
|
|
|
+- Handle<Object> setter, PropertyAttributes attributes);
|
|
|
+- static MaybeHandle<Object> DefineAccessor(LookupIterator* it,
|
|
|
+- Handle<Object> getter,
|
|
|
+- Handle<Object> setter,
|
|
|
+- PropertyAttributes attributes);
|
|
|
++ V8_EXPORT_PRIVATE static MaybeHandle<Object>
|
|
|
++ DefineOwnAccessorIgnoreAttributes(Handle<JSObject> object, Handle<Name> name,
|
|
|
++ Handle<Object> getter,
|
|
|
++ Handle<Object> setter,
|
|
|
++ PropertyAttributes attributes);
|
|
|
++ static MaybeHandle<Object> DefineOwnAccessorIgnoreAttributes(
|
|
|
++ LookupIterator* it, Handle<Object> getter, Handle<Object> setter,
|
|
|
++ PropertyAttributes attributes);
|
|
|
+
|
|
|
+ // Defines an AccessorInfo property on the given object.
|
|
|
+ V8_WARN_UNUSED_RESULT static MaybeHandle<Object> SetAccessor(
|
|
|
+diff --git a/src/runtime/runtime-object.cc b/src/runtime/runtime-object.cc
|
|
|
+index d72c1fd4e08e0d4620ff63da6aa49c20123ea6dc..c83ee5ed097c4e0c1cb8d4f703389df5c48799ad 100644
|
|
|
+--- a/src/runtime/runtime-object.cc
|
|
|
++++ b/src/runtime/runtime-object.cc
|
|
|
+@@ -1082,7 +1082,8 @@ RUNTIME_FUNCTION(Runtime_DefineAccessorPropertyUnchecked) {
|
|
|
+ auto attrs = PropertyAttributesFromInt(args.smi_value_at(4));
|
|
|
+
|
|
|
+ RETURN_FAILURE_ON_EXCEPTION(
|
|
|
+- isolate, JSObject::DefineAccessor(obj, name, getter, setter, attrs));
|
|
|
++ isolate, JSObject::DefineOwnAccessorIgnoreAttributes(obj, name, getter,
|
|
|
++ setter, attrs));
|
|
|
+ return ReadOnlyRoots(isolate).undefined_value();
|
|
|
+ }
|
|
|
+
|
|
|
+@@ -1209,8 +1210,8 @@ RUNTIME_FUNCTION(Runtime_DefineGetterPropertyUnchecked) {
|
|
|
+
|
|
|
+ RETURN_FAILURE_ON_EXCEPTION(
|
|
|
+ isolate,
|
|
|
+- JSObject::DefineAccessor(object, name, getter,
|
|
|
+- isolate->factory()->null_value(), attrs));
|
|
|
++ JSObject::DefineOwnAccessorIgnoreAttributes(
|
|
|
++ object, name, getter, isolate->factory()->null_value(), attrs));
|
|
|
+ return ReadOnlyRoots(isolate).undefined_value();
|
|
|
+ }
|
|
|
+
|
|
|
+@@ -1354,8 +1355,8 @@ RUNTIME_FUNCTION(Runtime_DefineSetterPropertyUnchecked) {
|
|
|
+
|
|
|
+ RETURN_FAILURE_ON_EXCEPTION(
|
|
|
+ isolate,
|
|
|
+- JSObject::DefineAccessor(object, name, isolate->factory()->null_value(),
|
|
|
+- setter, attrs));
|
|
|
++ JSObject::DefineOwnAccessorIgnoreAttributes(
|
|
|
++ object, name, isolate->factory()->null_value(), setter, attrs));
|
|
|
+ return ReadOnlyRoots(isolate).undefined_value();
|
|
|
+ }
|
|
|
+
|
|
|
+diff --git a/src/sandbox/testing.cc b/src/sandbox/testing.cc
|
|
|
+index adf86969f0eeeb8aa92056b40f7998eed8a473fe..0dec24c43fd02e7333380cf80b355e2e078b8ec3 100644
|
|
|
+--- a/src/sandbox/testing.cc
|
|
|
++++ b/src/sandbox/testing.cc
|
|
|
+@@ -160,7 +160,8 @@ void InstallGetter(Isolate* isolate, Handle<JSObject> object,
|
|
|
+ Handle<String> property_name = factory->NewStringFromAsciiChecked(name);
|
|
|
+ Handle<JSFunction> getter = CreateFunc(isolate, func, property_name, false);
|
|
|
+ Handle<Object> setter = factory->null_value();
|
|
|
+- JSObject::DefineAccessor(object, property_name, getter, setter, FROZEN);
|
|
|
++ JSObject::DefineOwnAccessorIgnoreAttributes(object, property_name, getter,
|
|
|
++ setter, FROZEN);
|
|
|
+ }
|
|
|
+
|
|
|
+ void InstallFunction(Isolate* isolate, Handle<JSObject> holder,
|
|
|
+diff --git a/test/cctest/test-code-stub-assembler.cc b/test/cctest/test-code-stub-assembler.cc
|
|
|
+index 5efe5281c26937cdf6e79e07cfb01b8233c3a1f4..4c2c8ed11eb7cdf504c9549d6c8c8ba61f7ce765 100644
|
|
|
+--- a/test/cctest/test-code-stub-assembler.cc
|
|
|
++++ b/test/cctest/test-code-stub-assembler.cc
|
|
|
+@@ -1178,7 +1178,9 @@ void AddProperties(Handle<JSObject> object, Handle<Name> names[],
|
|
|
+ Handle<AccessorPair> pair = Handle<AccessorPair>::cast(value);
|
|
|
+ Handle<Object> getter(pair->getter(), isolate);
|
|
|
+ Handle<Object> setter(pair->setter(), isolate);
|
|
|
+- JSObject::DefineAccessor(object, names[i], getter, setter, NONE).Check();
|
|
|
++ JSObject::DefineOwnAccessorIgnoreAttributes(object, names[i], getter,
|
|
|
++ setter, NONE)
|
|
|
++ .Check();
|
|
|
+ } else {
|
|
|
+ JSObject::AddProperty(isolate, object, names[i], value, NONE);
|
|
|
+ }
|