[shared-struct] Disallow property redefinition

Shared objects have fixed layout (i.e. immutable maps) and start off
sealed. Ordinary JS objects allow writable properties to be redefined to
be non-writable. This violates the fixed layout invariant and needs to
be disallowed.

Also contains a drive-by fix removing
@highestInstanceTypeWithinParentClassRange, which is unneeded.

Bug: chromium:1407595, v8:12547
Change-Id: I0257fa19f59ccfaaf0e07cb42aeedd71e132d21a
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4190525
Reviewed-by: Camillo Bruni <cbruni@chromium.org>
Commit-Queue: Shu-yu Guo <syg@chromium.org>
Cr-Commit-Position: refs/heads/main@{#85570}
This commit is contained in:
Shu-yu Guo 2023-01-30 14:39:29 -08:00 committed by V8 LUCI CQ
parent d3f27e067e
commit 15cc02b4e8
12 changed files with 196 additions and 83 deletions

View File

@ -1790,6 +1790,7 @@ filegroup(
"src/objects/js-shadow-realm-inl.h",
"src/objects/js-shared-array.h",
"src/objects/js-shared-array-inl.h",
"src/objects/js-struct.cc",
"src/objects/js-struct.h",
"src/objects/js-struct-inl.h",
"src/objects/js-temporal-objects.h",

View File

@ -4795,6 +4795,7 @@ v8_source_set("v8_base_without_compiler") {
"src/objects/js-segment-iterator.cc",
"src/objects/js-segmenter.cc",
"src/objects/js-segments.cc",
"src/objects/js-struct.cc",
"src/objects/js-temporal-objects.cc",
"src/objects/keys.cc",
"src/objects/literal-objects.cc",

View File

@ -99,6 +99,8 @@ namespace internal {
T(DebuggerType, "Debugger: Parameters have wrong types.") \
T(DeclarationMissingInitializer, "Missing initializer in % declaration") \
T(DefineDisallowed, "Cannot define property %, object is not extensible") \
T(DefineDisallowedFixedLayout, \
"Cannot define property %, object is fixed layout") \
T(DetachedOperation, "Cannot perform % on a detached ArrayBuffer") \
T(DoNotUse, "Do not use %; %") \
T(DuplicateTemplateProperty, "Object template has duplicate property '%'") \

View File

@ -1179,6 +1179,11 @@ Maybe<bool> JSReceiver::DefineOwnProperty(Isolate* isolate,
RETURN_FAILURE(isolate, kThrowOnError,
NewTypeError(MessageTemplate::kWasmObjectsAreOpaque));
}
if (object->IsAlwaysSharedSpaceJSObject()) {
return AlwaysSharedSpaceJSObject::DefineOwnProperty(
isolate, Handle<AlwaysSharedSpaceJSObject>::cast(object), key, desc,
should_throw);
}
// OrdinaryDefineOwnProperty, by virtue of calling
// DefineOwnPropertyIgnoreAttributes, can handle arguments
@ -4354,6 +4359,17 @@ Maybe<bool> JSObject::PreventExtensionsWithTransition(
isolate, PrototypeIterator::GetCurrent<JSObject>(iter), should_throw);
}
// Shared objects are designed to have fixed layout, i.e. their maps are
// effectively immutable. They are constructed seal, but the semantics of
// ordinary ECMAScript objects allow sealed to be upgraded to frozen. This
// upgrade violates the fixed layout invariant and is disallowed.
if (object->IsAlwaysSharedSpaceJSObject()) {
DCHECK(FastTestIntegrityLevel(*object, SEALED));
if (attrs != FROZEN) return Just(true);
RETURN_FAILURE(isolate, should_throw,
NewTypeError(MessageTemplate::kCannotFreeze));
}
if (object->map().has_named_interceptor() ||
object->map().has_indexed_interceptor()) {
MessageTemplate message = MessageTemplate::kNone;

49
src/objects/js-struct.cc Normal file
View File

@ -0,0 +1,49 @@
// Copyright 2023 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/objects/js-struct.h"
#include "src/objects/lookup-inl.h"
#include "src/objects/map-inl.h"
#include "src/objects/property-descriptor.h"
namespace v8 {
namespace internal {
// static
Maybe<bool> AlwaysSharedSpaceJSObject::DefineOwnProperty(
Isolate* isolate, Handle<AlwaysSharedSpaceJSObject> shared_obj,
Handle<Object> key, PropertyDescriptor* desc,
Maybe<ShouldThrow> should_throw) {
// Shared objects are designed to have fixed layout, i.e. their maps are
// effectively immutable. They are constructed seal, but the semantics of
// ordinary ECMAScript objects allow writable properties to be upgraded to
// non-writable properties. This upgrade violates the fixed layout invariant
// and is disallowed.
DCHECK(key->IsName() || key->IsNumber()); // |key| is a PropertyKey.
PropertyKey lookup_key(isolate, key);
LookupIterator it(isolate, shared_obj, lookup_key, LookupIterator::OWN);
PropertyDescriptor current;
MAYBE_RETURN(GetOwnPropertyDescriptor(&it, &current), Nothing<bool>());
// The only redefinition allowed is to set the value if all attributes match.
if (!it.IsFound() ||
PropertyDescriptor::IsDataDescriptor(desc) !=
PropertyDescriptor::IsDataDescriptor(&current) ||
desc->ToAttributes() != current.ToAttributes()) {
DCHECK(!shared_obj->map().is_extensible());
RETURN_FAILURE(isolate, GetShouldThrow(isolate, should_throw),
NewTypeError(MessageTemplate::kDefineDisallowedFixedLayout,
it.GetName()));
}
DCHECK(it.property_attributes() == desc->ToAttributes());
if (desc->has_value()) {
return Object::SetDataProperty(&it, desc->value());
}
return Just(true);
}
} // namespace internal
} // namespace v8

View File

@ -19,6 +19,11 @@ class AlwaysSharedSpaceJSObject
: public TorqueGeneratedAlwaysSharedSpaceJSObject<AlwaysSharedSpaceJSObject,
JSObject> {
public:
V8_WARN_UNUSED_RESULT static Maybe<bool> DefineOwnProperty(
Isolate* isolate, Handle<AlwaysSharedSpaceJSObject> shared_obj,
Handle<Object> key, PropertyDescriptor* desc,
Maybe<ShouldThrow> should_throw);
static_assert(kHeaderSize == JSObject::kHeaderSize);
TQ_OBJECT_CONSTRUCTORS(AlwaysSharedSpaceJSObject)
};

View File

@ -6,7 +6,6 @@
// shared space. Its instance type range is used to fast path the shared value
// barrier.
@abstract
@highestInstanceTypeWithinParentClassRange
extern class AlwaysSharedSpaceJSObject extends JSObject {
}

View File

@ -0,0 +1,40 @@
// Copyright 2023 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Flags: --harmony-struct
// Shared objects have fixed layout and cannot have their properties
// redefined. They are constructed sealed. In ordinary objects, sealed objects
// can be redefined to be frozen. This is disallowed for shared objects.
function TestSharedObjectCannotRedefineProperty(sharedObj) {
function TestRedefine(sharedObj, propName) {
if (Object.hasOwn(sharedObj, propName)) {
assertThrows(() => Object.defineProperty(sharedObj, propName, {
value: 99,
enumerable: true,
writable: false,
configurable: false
}));
Object.defineProperty(
sharedObj, propName,
{value: 99, enumerable: true, writable: true, configurable: false});
assertEquals(99, sharedObj[propName]);
}
}
TestRedefine(sharedObj, 'p');
TestRedefine(sharedObj, '0');
// Objects without any properties are a degenerate case and are considered
// frozen (or any integrity level, really).
if (Object.getOwnPropertyNames(sharedObj).length > 0) {
assertThrows(() => Object.freeze(sharedObj));
}
assertTrue(Object.isSealed(sharedObj));
}
TestSharedObjectCannotRedefineProperty(new Atomics.Condition());
TestSharedObjectCannotRedefineProperty(new Atomics.Mutex());
TestSharedObjectCannotRedefineProperty(new (new SharedStructType(['p'])));
TestSharedObjectCannotRedefineProperty(new SharedArray(1));

View File

@ -83,7 +83,7 @@ bytecodes: [
/* 48 E> */ B(DefineKeyedOwnProperty), R(this), R(0), U8(0), U8(0),
/* 53 S> */ B(LdaImmutableCurrentContextSlot), U8(3),
/* 58 E> */ B(GetKeyedProperty), R(this), U8(2),
B(Wide), B(LdaSmi), I16(310),
B(Wide), B(LdaSmi), I16(311),
B(Star2),
B(LdaConstant), U8(0),
B(Star3),
@ -115,7 +115,7 @@ bytecodes: [
/* 41 E> */ B(DefineKeyedOwnProperty), R(this), R(0), U8(0), U8(0),
/* 46 S> */ B(LdaImmutableCurrentContextSlot), U8(3),
/* 51 E> */ B(GetKeyedProperty), R(this), U8(2),
B(Wide), B(LdaSmi), I16(309),
B(Wide), B(LdaSmi), I16(310),
B(Star2),
B(LdaConstant), U8(0),
B(Star3),
@ -149,7 +149,7 @@ bytecodes: [
B(Star2),
B(LdaImmutableCurrentContextSlot), U8(3),
/* 58 E> */ B(GetKeyedProperty), R(this), U8(2),
B(Wide), B(LdaSmi), I16(310),
B(Wide), B(LdaSmi), I16(311),
B(Star3),
B(LdaConstant), U8(0),
B(Star4),
@ -181,7 +181,7 @@ bytecodes: [
/* 41 E> */ B(DefineKeyedOwnProperty), R(this), R(0), U8(0), U8(0),
/* 46 S> */ B(LdaImmutableCurrentContextSlot), U8(3),
/* 51 E> */ B(GetKeyedProperty), R(this), U8(2),
B(Wide), B(LdaSmi), I16(309),
B(Wide), B(LdaSmi), I16(310),
B(Star2),
B(LdaConstant), U8(0),
B(Star3),

View File

@ -58,7 +58,7 @@ bytecodes: [
B(Star2),
B(LdaImmutableCurrentContextSlot), U8(3),
/* 54 E> */ B(GetKeyedProperty), R(this), U8(2),
B(Wide), B(LdaSmi), I16(308),
B(Wide), B(LdaSmi), I16(309),
B(Star3),
B(LdaConstant), U8(0),
B(Star4),
@ -91,7 +91,7 @@ bytecodes: [
/* 44 E> */ B(DefineKeyedOwnProperty), R(this), R(0), U8(0), U8(0),
/* 49 S> */ B(LdaImmutableCurrentContextSlot), U8(3),
/* 54 E> */ B(GetKeyedProperty), R(this), U8(2),
B(Wide), B(LdaSmi), I16(308),
B(Wide), B(LdaSmi), I16(309),
B(Star2),
B(LdaConstant), U8(0),
B(Star3),

View File

@ -24,7 +24,7 @@ bytecodes: [
B(TestReferenceEqual), R(this),
B(Mov), R(this), R(1),
B(JumpIfTrue), U8(16),
B(Wide), B(LdaSmi), I16(302),
B(Wide), B(LdaSmi), I16(303),
B(Star2),
B(LdaConstant), U8(0),
B(Star3),
@ -61,13 +61,13 @@ bytecodes: [
B(TestReferenceEqual), R(this),
B(Mov), R(this), R(0),
B(JumpIfTrue), U8(16),
B(Wide), B(LdaSmi), I16(302),
B(Wide), B(LdaSmi), I16(303),
B(Star2),
B(LdaConstant), U8(0),
B(Star3),
/* 61 E> */ B(CallRuntime), U16(Runtime::kNewTypeError), R(2), U8(2),
B(Throw),
B(Wide), B(LdaSmi), I16(308),
B(Wide), B(LdaSmi), I16(309),
B(Star2),
B(LdaConstant), U8(1),
B(Star3),
@ -99,13 +99,13 @@ bytecodes: [
B(TestReferenceEqual), R(this),
B(Mov), R(this), R(0),
B(JumpIfTrue), U8(16),
B(Wide), B(LdaSmi), I16(302),
B(Wide), B(LdaSmi), I16(303),
B(Star1),
B(LdaConstant), U8(0),
B(Star2),
/* 61 E> */ B(CallRuntime), U16(Runtime::kNewTypeError), R(1), U8(2),
B(Throw),
B(Wide), B(LdaSmi), I16(308),
B(Wide), B(LdaSmi), I16(309),
B(Star1),
B(LdaConstant), U8(1),
B(Star2),
@ -145,7 +145,7 @@ bytecodes: [
B(TestReferenceEqual), R(this),
B(Mov), R(this), R(0),
B(JumpIfTrue), U8(16),
B(Wide), B(LdaSmi), I16(302),
B(Wide), B(LdaSmi), I16(303),
B(Star2),
B(LdaConstant), U8(0),
B(Star3),
@ -167,7 +167,7 @@ bytecodes: [
B(TestReferenceEqual), R(this),
B(Mov), R(this), R(0),
B(JumpIfTrue), U8(16),
B(Wide), B(LdaSmi), I16(302),
B(Wide), B(LdaSmi), I16(303),
B(Star3),
B(LdaConstant), U8(0),
B(Star4),
@ -182,7 +182,7 @@ bytecodes: [
B(TestReferenceEqual), R(this),
B(Mov), R(this), R(0),
B(JumpIfTrue), U8(16),
B(Wide), B(LdaSmi), I16(302),
B(Wide), B(LdaSmi), I16(303),
B(Star2),
B(LdaConstant), U8(0),
B(Star3),
@ -216,13 +216,13 @@ bytecodes: [
B(TestReferenceEqual), R(this),
B(Mov), R(this), R(0),
B(JumpIfTrue), U8(16),
B(Wide), B(LdaSmi), I16(302),
B(Wide), B(LdaSmi), I16(303),
B(Star1),
B(LdaConstant), U8(0),
B(Star2),
/* 65 E> */ B(CallRuntime), U16(Runtime::kNewTypeError), R(1), U8(2),
B(Throw),
B(Wide), B(LdaSmi), I16(310),
B(Wide), B(LdaSmi), I16(311),
B(Star1),
B(LdaConstant), U8(1),
B(Star2),
@ -253,13 +253,13 @@ bytecodes: [
B(TestReferenceEqual), R(this),
B(Mov), R(this), R(0),
B(JumpIfTrue), U8(16),
B(Wide), B(LdaSmi), I16(302),
B(Wide), B(LdaSmi), I16(303),
B(Star1),
B(LdaConstant), U8(0),
B(Star2),
/* 58 E> */ B(CallRuntime), U16(Runtime::kNewTypeError), R(1), U8(2),
B(Throw),
B(Wide), B(LdaSmi), I16(309),
B(Wide), B(LdaSmi), I16(310),
B(Star1),
B(LdaConstant), U8(1),
B(Star2),
@ -292,13 +292,13 @@ bytecodes: [
B(TestReferenceEqual), R(this),
B(Mov), R(this), R(0),
B(JumpIfTrue), U8(16),
B(Wide), B(LdaSmi), I16(302),
B(Wide), B(LdaSmi), I16(303),
B(Star2),
B(LdaConstant), U8(0),
B(Star3),
/* 65 E> */ B(CallRuntime), U16(Runtime::kNewTypeError), R(2), U8(2),
B(Throw),
B(Wide), B(LdaSmi), I16(310),
B(Wide), B(LdaSmi), I16(311),
B(Star2),
B(LdaConstant), U8(1),
B(Star3),
@ -327,7 +327,7 @@ bytecode array length: 19
bytecodes: [
/* 46 S> */ B(LdaImmutableCurrentContextSlot), U8(3),
/* 51 E> */ B(GetKeyedProperty), R(this), U8(0),
B(Wide), B(LdaSmi), I16(309),
B(Wide), B(LdaSmi), I16(310),
B(Star1),
B(LdaConstant), U8(0),
B(Star2),

View File

@ -231,65 +231,65 @@ INSTANCE_TYPES = {
2093: "JS_MAP_VALUE_ITERATOR_TYPE",
2094: "JS_SET_KEY_VALUE_ITERATOR_TYPE",
2095: "JS_SET_VALUE_ITERATOR_TYPE",
2096: "JS_GENERATOR_OBJECT_TYPE",
2097: "JS_ASYNC_FUNCTION_OBJECT_TYPE",
2098: "JS_ASYNC_GENERATOR_OBJECT_TYPE",
2099: "JS_MAP_TYPE",
2100: "JS_SET_TYPE",
2101: "JS_WEAK_MAP_TYPE",
2102: "JS_WEAK_SET_TYPE",
2103: "JS_ARGUMENTS_OBJECT_TYPE",
2104: "JS_ARRAY_TYPE",
2105: "JS_ARRAY_ITERATOR_TYPE",
2106: "JS_ASYNC_FROM_SYNC_ITERATOR_TYPE",
2107: "JS_COLLATOR_TYPE",
2108: "JS_CONTEXT_EXTENSION_OBJECT_TYPE",
2109: "JS_DATE_TYPE",
2110: "JS_DATE_TIME_FORMAT_TYPE",
2111: "JS_DISPLAY_NAMES_TYPE",
2112: "JS_DURATION_FORMAT_TYPE",
2113: "JS_ERROR_TYPE",
2114: "JS_EXTERNAL_OBJECT_TYPE",
2115: "JS_FINALIZATION_REGISTRY_TYPE",
2116: "JS_LIST_FORMAT_TYPE",
2117: "JS_LOCALE_TYPE",
2118: "JS_MESSAGE_OBJECT_TYPE",
2119: "JS_NUMBER_FORMAT_TYPE",
2120: "JS_PLURAL_RULES_TYPE",
2121: "JS_RAW_JSON_TYPE",
2122: "JS_REG_EXP_TYPE",
2123: "JS_REG_EXP_STRING_ITERATOR_TYPE",
2124: "JS_RELATIVE_TIME_FORMAT_TYPE",
2125: "JS_SEGMENT_ITERATOR_TYPE",
2126: "JS_SEGMENTER_TYPE",
2127: "JS_SEGMENTS_TYPE",
2128: "JS_SHADOW_REALM_TYPE",
2129: "JS_STRING_ITERATOR_TYPE",
2130: "JS_TEMPORAL_CALENDAR_TYPE",
2131: "JS_TEMPORAL_DURATION_TYPE",
2132: "JS_TEMPORAL_INSTANT_TYPE",
2133: "JS_TEMPORAL_PLAIN_DATE_TYPE",
2134: "JS_TEMPORAL_PLAIN_DATE_TIME_TYPE",
2135: "JS_TEMPORAL_PLAIN_MONTH_DAY_TYPE",
2136: "JS_TEMPORAL_PLAIN_TIME_TYPE",
2137: "JS_TEMPORAL_PLAIN_YEAR_MONTH_TYPE",
2138: "JS_TEMPORAL_TIME_ZONE_TYPE",
2139: "JS_TEMPORAL_ZONED_DATE_TIME_TYPE",
2140: "JS_V8_BREAK_ITERATOR_TYPE",
2141: "JS_WEAK_REF_TYPE",
2142: "WASM_EXCEPTION_PACKAGE_TYPE",
2143: "WASM_GLOBAL_OBJECT_TYPE",
2144: "WASM_INSTANCE_OBJECT_TYPE",
2145: "WASM_MEMORY_OBJECT_TYPE",
2146: "WASM_MODULE_OBJECT_TYPE",
2147: "WASM_SUSPENDER_OBJECT_TYPE",
2148: "WASM_TABLE_OBJECT_TYPE",
2149: "WASM_TAG_OBJECT_TYPE",
2150: "WASM_VALUE_OBJECT_TYPE",
2151: "JS_ATOMICS_CONDITION_TYPE",
2152: "JS_ATOMICS_MUTEX_TYPE",
2153: "JS_SHARED_ARRAY_TYPE",
2154: "JS_SHARED_STRUCT_TYPE",
2096: "JS_ATOMICS_CONDITION_TYPE",
2097: "JS_ATOMICS_MUTEX_TYPE",
2098: "JS_SHARED_ARRAY_TYPE",
2099: "JS_SHARED_STRUCT_TYPE",
2100: "JS_GENERATOR_OBJECT_TYPE",
2101: "JS_ASYNC_FUNCTION_OBJECT_TYPE",
2102: "JS_ASYNC_GENERATOR_OBJECT_TYPE",
2103: "JS_MAP_TYPE",
2104: "JS_SET_TYPE",
2105: "JS_WEAK_MAP_TYPE",
2106: "JS_WEAK_SET_TYPE",
2107: "JS_ARGUMENTS_OBJECT_TYPE",
2108: "JS_ARRAY_TYPE",
2109: "JS_ARRAY_ITERATOR_TYPE",
2110: "JS_ASYNC_FROM_SYNC_ITERATOR_TYPE",
2111: "JS_COLLATOR_TYPE",
2112: "JS_CONTEXT_EXTENSION_OBJECT_TYPE",
2113: "JS_DATE_TYPE",
2114: "JS_DATE_TIME_FORMAT_TYPE",
2115: "JS_DISPLAY_NAMES_TYPE",
2116: "JS_DURATION_FORMAT_TYPE",
2117: "JS_ERROR_TYPE",
2118: "JS_EXTERNAL_OBJECT_TYPE",
2119: "JS_FINALIZATION_REGISTRY_TYPE",
2120: "JS_LIST_FORMAT_TYPE",
2121: "JS_LOCALE_TYPE",
2122: "JS_MESSAGE_OBJECT_TYPE",
2123: "JS_NUMBER_FORMAT_TYPE",
2124: "JS_PLURAL_RULES_TYPE",
2125: "JS_RAW_JSON_TYPE",
2126: "JS_REG_EXP_TYPE",
2127: "JS_REG_EXP_STRING_ITERATOR_TYPE",
2128: "JS_RELATIVE_TIME_FORMAT_TYPE",
2129: "JS_SEGMENT_ITERATOR_TYPE",
2130: "JS_SEGMENTER_TYPE",
2131: "JS_SEGMENTS_TYPE",
2132: "JS_SHADOW_REALM_TYPE",
2133: "JS_STRING_ITERATOR_TYPE",
2134: "JS_TEMPORAL_CALENDAR_TYPE",
2135: "JS_TEMPORAL_DURATION_TYPE",
2136: "JS_TEMPORAL_INSTANT_TYPE",
2137: "JS_TEMPORAL_PLAIN_DATE_TYPE",
2138: "JS_TEMPORAL_PLAIN_DATE_TIME_TYPE",
2139: "JS_TEMPORAL_PLAIN_MONTH_DAY_TYPE",
2140: "JS_TEMPORAL_PLAIN_TIME_TYPE",
2141: "JS_TEMPORAL_PLAIN_YEAR_MONTH_TYPE",
2142: "JS_TEMPORAL_TIME_ZONE_TYPE",
2143: "JS_TEMPORAL_ZONED_DATE_TIME_TYPE",
2144: "JS_V8_BREAK_ITERATOR_TYPE",
2145: "JS_WEAK_REF_TYPE",
2146: "WASM_EXCEPTION_PACKAGE_TYPE",
2147: "WASM_GLOBAL_OBJECT_TYPE",
2148: "WASM_INSTANCE_OBJECT_TYPE",
2149: "WASM_MEMORY_OBJECT_TYPE",
2150: "WASM_MODULE_OBJECT_TYPE",
2151: "WASM_SUSPENDER_OBJECT_TYPE",
2152: "WASM_TABLE_OBJECT_TYPE",
2153: "WASM_TAG_OBJECT_TYPE",
2154: "WASM_VALUE_OBJECT_TYPE",
}
# List of known V8 maps.
@ -481,8 +481,8 @@ KNOWN_MAPS = {
("read_only_space", 0x03e95): (272, "WasmTypeInfoMap"),
("read_only_space", 0x03ebd): (268, "WasmContinuationObjectMap"),
("read_only_space", 0x03ee5): (274, "WeakCellMap"),
("old_space", 0x043bd): (2114, "ExternalMap"),
("old_space", 0x043e5): (2118, "JSMessageObjectMap"),
("old_space", 0x043bd): (2118, "ExternalMap"),
("old_space", 0x043e5): (2122, "JSMessageObjectMap"),
}
# List of known V8 objects.