diff --git a/Userland/Libraries/LibWeb/FileAPI/File.cpp b/Userland/Libraries/LibWeb/FileAPI/File.cpp index 507f5e47a08..5387cc28ae0 100644 --- a/Userland/Libraries/LibWeb/FileAPI/File.cpp +++ b/Userland/Libraries/LibWeb/FileAPI/File.cpp @@ -104,7 +104,7 @@ WebIDL::ExceptionOr File::serialization_steps(HTML::SerializationRecord& r TRY(HTML::serialize_string(vm, record, m_name)); // 4. Set serialized.[[LastModified]] to the value of value’s lastModified attribute. - HTML::serialize_i64(record, m_last_modified); + HTML::serialize_primitive_type(record, m_last_modified); return {}; } @@ -126,7 +126,7 @@ WebIDL::ExceptionOr File::deserialization_steps(ReadonlySpan const& r m_name = TRY(HTML::deserialize_string(vm, record, position)); // 4. Initialize the value of value’s lastModified attribute to serialized.[[LastModified]]. - m_last_modified = HTML::deserialize_i64(record, position); + m_last_modified = HTML::deserialize_primitive_type(record, position); return {}; } diff --git a/Userland/Libraries/LibWeb/HTML/StructuredSerialize.cpp b/Userland/Libraries/LibWeb/HTML/StructuredSerialize.cpp index 4e4307111a0..4f61d46d233 100644 --- a/Userland/Libraries/LibWeb/HTML/StructuredSerialize.cpp +++ b/Userland/Libraries/LibWeb/HTML/StructuredSerialize.cpp @@ -280,7 +280,7 @@ public: // FIXME: 6. User agents should attach a serialized representation of any interesting accompanying data which are not yet specified, notably the stack property, to serialized. m_serialized.append(ValueTag::ErrorObject); m_serialized.append(type); - m_serialized.append(message.has_value()); + serialize_primitive_type(m_serialized, message.has_value()); if (message.has_value()) TRY(serialize_string(m_vm, m_serialized, *message)); } @@ -294,7 +294,7 @@ public: // 3. Set serialized to { [[Type]]: "Array", [[Length]]: valueLen, [[Properties]]: a new empty List }. m_serialized.append(ValueTag::ArrayObject); - m_serialized.append(bit_cast(&length), 2); + serialize_primitive_type(m_serialized, length); // 4. Set deep to true. deep = true; @@ -377,8 +377,7 @@ public: // 1. If entry is not the special value empty, append entry to copiedList. copied_list.append(entry.key); } - u64 size = set.set_size(); - m_serialized.append(bit_cast(&size), 2); + serialize_primitive_type(m_serialized, set.set_size()); // 3. For each entry of copiedList: for (auto copied_value : copied_list) { // 1. Let serializedEntry be ? StructuredSerializeInternal(entry, forStorage, memory). @@ -395,7 +394,7 @@ public: else { u64 property_count = 0; auto count_offset = m_serialized.size(); - m_serialized.append(bit_cast(&property_count), 2); + serialize_primitive_type(m_serialized, property_count); for (auto key : MUST(value.as_object().enumerable_own_property_names(JS::Object::PropertyKind::Key))) { auto property_key = MUST(JS::PropertyKey::from_value(m_vm, key)); @@ -433,14 +432,13 @@ private: void serialize_boolean_primitive(SerializationRecord& serialized, JS::Value& value) { VERIFY(value.is_boolean()); - serialized.append(static_cast(value.as_bool())); + serialize_primitive_type(serialized, value.as_bool()); } void serialize_number_primitive(SerializationRecord& serialized, JS::Value& value) { VERIFY(value.is_number()); - double number = value.as_double(); - serialized.append(bit_cast(&number), 2); + serialize_primitive_type(serialized, value.as_double()); } WebIDL::ExceptionOr serialize_big_int_primitive(JS::VM& vm, SerializationRecord& serialized, JS::Value& value) @@ -462,15 +460,14 @@ void serialize_boolean_object(SerializationRecord& serialized, JS::Value& value) { VERIFY(value.is_object() && is(value.as_object())); auto& boolean_object = static_cast(value.as_object()); - serialized.append(bit_cast(static_cast(boolean_object.boolean()))); + serialize_primitive_type(serialized, boolean_object.boolean()); } void serialize_number_object(SerializationRecord& serialized, JS::Value& value) { VERIFY(value.is_object() && is(value.as_object())); auto& number_object = static_cast(value.as_object()); - double const number = number_object.number(); - serialized.append(bit_cast(&number), 2); + serialize_primitive_type(serialized, number_object.number()); } WebIDL::ExceptionOr serialize_big_int_object(JS::VM& vm, SerializationRecord& serialized, JS::Value& value) @@ -493,8 +490,7 @@ void serialize_date_object(SerializationRecord& serialized, JS::Value& value) { VERIFY(value.is_object() && is(value.as_object())); auto& date_object = static_cast(value.as_object()); - double const date_value = date_object.date_value(); - serialized.append(bit_cast(&date_value), 2); + serialize_primitive_type(serialized, date_object.date_value()); } WebIDL::ExceptionOr serialize_reg_exp_object(JS::VM& vm, SerializationRecord& serialized, JS::Value& value) @@ -509,21 +505,11 @@ WebIDL::ExceptionOr serialize_reg_exp_object(JS::VM& vm, SerializationReco return {}; } -void serialize_u64(SerializationRecord& serialized, u64 value) -{ - serialized.append(bit_cast(&value), 2); -} - -void serialize_i64(SerializationRecord& serialized, i64 value) -{ - serialized.append(bit_cast(&value), 2); -} - WebIDL::ExceptionOr serialize_bytes(JS::VM& vm, Vector& vector, ReadonlyBytes bytes) { // Append size of the buffer to the serialized structure. u64 const size = bytes.size(); - serialize_u64(vector, size); + serialize_primitive_type(vector, size); // Append the bytes of the buffer to the serialized structure. u64 byte_position = 0; while (byte_position < size) { @@ -646,8 +632,8 @@ WebIDL::ExceptionOr serialize_viewed_array_buffer(JS::VM& vm, Vector& vector.append(ValueTag::ArrayBufferView); vector.extend(move(buffer_serialized)); // [[ArrayBufferSerialized]] TRY(serialize_string(vm, vector, "DataView"_string)); // [[Constructor]] - vector.append(JS::get_view_byte_length(view_record)); - vector.append(view.byte_offset()); + serialize_primitive_type(vector, JS::get_view_byte_length(view_record)); + serialize_primitive_type(vector, view.byte_offset()); } // 6. Otherwise: @@ -660,9 +646,9 @@ WebIDL::ExceptionOr serialize_viewed_array_buffer(JS::VM& vm, Vector& vector.append(ValueTag::ArrayBufferView); vector.extend(move(buffer_serialized)); // [[ArrayBufferSerialized]] TRY(serialize_string(vm, vector, view.element_name())); // [[Constructor]] - vector.append(JS::typed_array_byte_length(view_record)); - vector.append(view.byte_offset()); - vector.append(JS::typed_array_length(view_record)); + serialize_primitive_type(vector, JS::typed_array_byte_length(view_record)); + serialize_primitive_type(vector, view.byte_offset()); + serialize_primitive_type(vector, JS::typed_array_length(view_record)); } return {}; } @@ -784,13 +770,13 @@ public: auto array_buffer_value = TRY(deserialize()); auto& array_buffer = verify_cast(array_buffer_value.as_object()); auto constructor_name = TRY(deserialize_string(m_vm, m_serialized, m_position)); - u32 byte_length = m_serialized[m_position++]; - u32 byte_offset = m_serialized[m_position++]; + u32 byte_length = deserialize_primitive_type(m_serialized, m_position); + u32 byte_offset = deserialize_primitive_type(m_serialized, m_position); if (constructor_name == "DataView"sv) { value = JS::DataView::create(*realm, &array_buffer, byte_length, byte_offset); } else { - u32 array_length = m_serialized[m_position++]; + u32 array_length = deserialize_primitive_type(m_serialized, m_position); JS::GCPtr typed_array_ptr; #define CREATE_TYPED_ARRAY(ClassName) \ if (constructor_name == #ClassName##sv) \ @@ -830,7 +816,7 @@ public: auto& realm = *m_vm.current_realm(); // 1. Let outputProto be targetRealm.[[Intrinsics]].[[%Array.prototype%]]. // 2. Set value to ! ArrayCreate(serialized.[[Length]], outputProto). - auto length = read_u64(); + auto length = deserialize_primitive_type(m_serialized, m_position); value = MUST(JS::Array::create(realm, length)); // 3. Set deep to true. deep = true; @@ -849,7 +835,7 @@ public: case ValueTag::ErrorObject: { auto& realm = *m_vm.current_realm(); auto type = static_cast(m_serialized[m_position++]); - auto has_message = static_cast(m_serialized[m_position++]); + auto has_message = deserialize_primitive_type(m_serialized, m_position); if (has_message) { auto message = TRY(deserialize_string(m_vm, m_serialized, m_position)); switch (type) { @@ -906,7 +892,7 @@ public: // 1. If serialized.[[Type]] is "Map", then: if (tag == ValueTag::MapObject) { auto& map = static_cast(value.as_object()); - auto length = read_u64(); + auto length = deserialize_primitive_type(m_serialized, m_position); // 1. For each Record { [[Key]], [[Value]] } entry of serialized.[[MapData]]: for (u64 i = 0u; i < length; ++i) { // 1. Let deserializedKey be ? StructuredDeserialize(entry.[[Key]], targetRealm, memory). @@ -923,7 +909,7 @@ public: // 2. Otherwise, if serialized.[[Type]] is "Set", then: else if (tag == ValueTag::SetObject) { auto& set = static_cast(value.as_object()); - auto length = read_u64(); + auto length = deserialize_primitive_type(m_serialized, m_position); // 1. For each entry of serialized.[[SetData]]: for (u64 i = 0u; i < length; ++i) { // 1. Let deserializedEntry be ? StructuredDeserialize(entry, targetRealm, memory). @@ -937,7 +923,7 @@ public: // 3. Otherwise, if serialized.[[Type]] is "Array" or "Object", then: else if (tag == ValueTag::ArrayObject || tag == ValueTag::Object) { auto& object = value.as_object(); - auto length = read_u64(); + auto length = deserialize_primitive_type(m_serialized, m_position); // 1. For each Record { [[Key]], [[Value]] } entry of serialized.[[Properties]]: for (u64 i = 0u; i < length; ++i) { auto key = TRY(deserialize_string(m_vm, m_serialized, m_position)); @@ -971,14 +957,6 @@ private: size_t m_position { 0 }; JS::MarkedVector m_memory; // Index -> JS value - u64 read_u64() - { - u64 value; - memcpy(&value, m_serialized.offset_pointer(m_position), sizeof(value)); - m_position += 2; - return value; - } - static WebIDL::ExceptionOr> create_serialized_type(StringView interface_name, JS::Realm& realm) { if (interface_name == "Blob"sv) @@ -1000,18 +978,12 @@ private: bool deserialize_boolean_primitive(ReadonlySpan const& serialized, size_t& position) { - VERIFY(position < serialized.size()); - return static_cast(serialized[position++]); + return deserialize_primitive_type(serialized, position); } double deserialize_number_primitive(ReadonlySpan const& serialized, size_t& position) { - VERIFY(position + 2 <= serialized.size()); - u32 const bits[2] { - serialized[position++], - serialized[position++], - }; - return *bit_cast(&bits); + return deserialize_primitive_type(serialized, position); } JS::NonnullGCPtr deserialize_boolean_object(JS::Realm& realm, ReadonlySpan const& serialized, size_t& position) @@ -1040,12 +1012,7 @@ WebIDL::ExceptionOr> deserialize_string_objec JS::NonnullGCPtr deserialize_date_object(JS::Realm& realm, ReadonlySpan const& serialized, size_t& position) { - VERIFY(position + 2 <= serialized.size()); - u32 const bits[2] { - serialized[position++], - serialized[position++], - }; - auto double_value = *bit_cast(&bits); + auto double_value = deserialize_primitive_type(serialized, position); return JS::Date::create(realm, double_value); } @@ -1056,29 +1023,9 @@ WebIDL::ExceptionOr> deserialize_reg_exp_obje return TRY(JS::regexp_create(realm.vm(), move(pattern), move(flags))); } -u64 deserialize_u64(ReadonlySpan const& serialized, size_t& position) -{ - VERIFY(position + 2 <= serialized.size()); - u32 const bits[2] { - serialized[position++], - serialized[position++], - }; - return *bit_cast(&bits); -} - -i64 deserialize_i64(ReadonlySpan const& serialized, size_t& position) -{ - VERIFY(position + 2 <= serialized.size()); - u32 const bits[2] { - serialized[position++], - serialized[position++], - }; - return *bit_cast(&bits); -} - WebIDL::ExceptionOr deserialize_bytes(JS::VM& vm, ReadonlySpan vector, size_t& position) { - u64 const size = deserialize_u64(vector, position); + u64 const size = deserialize_primitive_type(vector, position); auto bytes = TRY_OR_THROW_OOM(vm, ByteBuffer::create_uninitialized(size)); u64 byte_position = 0; diff --git a/Userland/Libraries/LibWeb/HTML/StructuredSerialize.h b/Userland/Libraries/LibWeb/HTML/StructuredSerialize.h index 014d6978b5a..cce43184271 100644 --- a/Userland/Libraries/LibWeb/HTML/StructuredSerialize.h +++ b/Userland/Libraries/LibWeb/HTML/StructuredSerialize.h @@ -61,8 +61,18 @@ WebIDL::ExceptionOr serialize_big_int_object(JS::VM& vm, SerializationReco WebIDL::ExceptionOr serialize_string_object(JS::VM& vm, SerializationRecord& serialized, JS::Value& value); void serialize_date_object(SerializationRecord& serialized, JS::Value& value); WebIDL::ExceptionOr serialize_reg_exp_object(JS::VM& vm, SerializationRecord& serialized, JS::Value& value); -void serialize_u64(SerializationRecord& serialized, u64 value); -void serialize_i64(SerializationRecord& serialized, i64 value); + +template +requires(IsIntegral || IsFloatingPoint) +void serialize_primitive_type(SerializationRecord& serialized, T value) +{ + if constexpr (sizeof(T) < sizeof(u32)) { + // NOTE: If the value is smaller than a u32, we can just store it directly. + serialized.append(static_cast(value)); + return; + } + serialized.append(bit_cast(&value), sizeof(T) / 4); +} WebIDL::ExceptionOr serialize_bytes(JS::VM& vm, Vector& vector, ReadonlyBytes bytes); WebIDL::ExceptionOr serialize_string(JS::VM& vm, Vector& vector, DeprecatedFlyString const& string); @@ -80,8 +90,19 @@ WebIDL::ExceptionOr> deserialize_big_int_obje WebIDL::ExceptionOr> deserialize_string_object(JS::Realm& realm, ReadonlySpan const& serialized, size_t& position); JS::NonnullGCPtr deserialize_date_object(JS::Realm& realm, ReadonlySpan const& serialized, size_t& position); WebIDL::ExceptionOr> deserialize_reg_exp_object(JS::Realm& realm, ReadonlySpan const& serialized, size_t& position); -u64 deserialize_u64(ReadonlySpan const& serialized, size_t& position); -i64 deserialize_i64(ReadonlySpan const& serialized, size_t& position); + +template +requires(IsIntegral || IsFloatingPoint) +T deserialize_primitive_type(ReadonlySpan const& serialized, size_t& position) +{ + T value; + // NOTE: Make sure we always round up, otherwise Ts that are less than 32 bit will end up with a size of 0. + auto size = 1 + ((sizeof(value) - 1) / 4); + VERIFY(position + size <= serialized.size()); + memcpy(&value, serialized.offset_pointer(position), sizeof(value)); + position += size; + return value; +} WebIDL::ExceptionOr deserialize_bytes(JS::VM& vm, ReadonlySpan vector, size_t& position); WebIDL::ExceptionOr deserialize_string(JS::VM& vm, ReadonlySpan vector, size_t& position);