Commit 3483b970 authored by Marja Hölttä's avatar Marja Hölttä Committed by V8 LUCI CQ

[rab/gsab] Fix flag mismatch in serialized data

Bug: v8:11111,chromium:1339648
Change-Id: I3b472f74f37a4e1514ce20635b16970e95a36e15
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3735162Reviewed-by: 's avatarShu-yu Guo <syg@chromium.org>
Commit-Queue: Marja Hölttä <marja@chromium.org>
Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/main@{#81598}
parent 3f7c53b0
...@@ -65,6 +65,17 @@ static const uint32_t kLatestVersion = 15; ...@@ -65,6 +65,17 @@ static const uint32_t kLatestVersion = 15;
static_assert(kLatestVersion == v8::CurrentValueSerializerFormatVersion(), static_assert(kLatestVersion == v8::CurrentValueSerializerFormatVersion(),
"Exported format version must match latest version."); "Exported format version must match latest version.");
namespace {
// For serializing JSArrayBufferView flags. Instead of serializing /
// deserializing the flags directly, we serialize them bit by bit. This is for
// ensuring backwards compatilibity in the case where the representation
// changes. Note that the ValueSerializer data can be stored on disk.
using JSArrayBufferViewIsLengthTracking = base::BitField<bool, 0, 1>;
using JSArrayBufferViewIsBackedByRab =
JSArrayBufferViewIsLengthTracking::Next<bool, 1>;
} // namespace
template <typename T> template <typename T>
static size_t BytesNeededForVarint(T value) { static size_t BytesNeededForVarint(T value) {
static_assert(std::is_integral<T>::value && std::is_unsigned<T>::value, static_assert(std::is_integral<T>::value && std::is_unsigned<T>::value,
...@@ -934,6 +945,8 @@ Maybe<bool> ValueSerializer::WriteJSArrayBuffer( ...@@ -934,6 +945,8 @@ Maybe<bool> ValueSerializer::WriteJSArrayBuffer(
if (byte_length > std::numeric_limits<uint32_t>::max()) { if (byte_length > std::numeric_limits<uint32_t>::max()) {
return ThrowDataCloneError(MessageTemplate::kDataCloneError, array_buffer); return ThrowDataCloneError(MessageTemplate::kDataCloneError, array_buffer);
} }
// TODO(v8:11111): Support RAB / GSAB. The wire version will need to be
// bumped.
WriteTag(SerializationTag::kArrayBuffer); WriteTag(SerializationTag::kArrayBuffer);
WriteVarint<uint32_t>(byte_length); WriteVarint<uint32_t>(byte_length);
WriteRawBytes(array_buffer->backing_store(), byte_length); WriteRawBytes(array_buffer->backing_store(), byte_length);
...@@ -962,7 +975,10 @@ Maybe<bool> ValueSerializer::WriteJSArrayBufferView(JSArrayBufferView view) { ...@@ -962,7 +975,10 @@ Maybe<bool> ValueSerializer::WriteJSArrayBufferView(JSArrayBufferView view) {
WriteVarint(static_cast<uint8_t>(tag)); WriteVarint(static_cast<uint8_t>(tag));
WriteVarint(static_cast<uint32_t>(view.byte_offset())); WriteVarint(static_cast<uint32_t>(view.byte_offset()));
WriteVarint(static_cast<uint32_t>(view.byte_length())); WriteVarint(static_cast<uint32_t>(view.byte_length()));
WriteVarint(static_cast<uint32_t>(view.bit_field())); uint32_t flags =
JSArrayBufferViewIsLengthTracking::encode(view.is_length_tracking()) |
JSArrayBufferViewIsBackedByRab::encode(view.is_backed_by_rab());
WriteVarint(flags);
return ThrowIfOutOfMemory(); return ThrowIfOutOfMemory();
} }
...@@ -2003,7 +2019,7 @@ MaybeHandle<JSArrayBuffer> ValueDeserializer::ReadTransferredJSArrayBuffer() { ...@@ -2003,7 +2019,7 @@ MaybeHandle<JSArrayBuffer> ValueDeserializer::ReadTransferredJSArrayBuffer() {
MaybeHandle<JSArrayBufferView> ValueDeserializer::ReadJSArrayBufferView( MaybeHandle<JSArrayBufferView> ValueDeserializer::ReadJSArrayBufferView(
Handle<JSArrayBuffer> buffer) { Handle<JSArrayBuffer> buffer) {
uint32_t buffer_byte_length = static_cast<uint32_t>(buffer->byte_length()); uint32_t buffer_byte_length = static_cast<uint32_t>(buffer->GetByteLength());
uint8_t tag = 0; uint8_t tag = 0;
uint32_t byte_offset = 0; uint32_t byte_offset = 0;
uint32_t byte_length = 0; uint32_t byte_length = 0;
...@@ -2028,7 +2044,9 @@ MaybeHandle<JSArrayBufferView> ValueDeserializer::ReadJSArrayBufferView( ...@@ -2028,7 +2044,9 @@ MaybeHandle<JSArrayBufferView> ValueDeserializer::ReadJSArrayBufferView(
Handle<JSDataView> data_view = Handle<JSDataView> data_view =
isolate_->factory()->NewJSDataView(buffer, byte_offset, byte_length); isolate_->factory()->NewJSDataView(buffer, byte_offset, byte_length);
AddObjectWithID(id, data_view); AddObjectWithID(id, data_view);
data_view->set_bit_field(flags); if (!ValidateAndSetJSArrayBufferViewFlags(*data_view, *buffer, flags)) {
return MaybeHandle<JSArrayBufferView>();
}
return data_view; return data_view;
} }
#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) \ #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) \
...@@ -2045,11 +2063,39 @@ MaybeHandle<JSArrayBufferView> ValueDeserializer::ReadJSArrayBufferView( ...@@ -2045,11 +2063,39 @@ MaybeHandle<JSArrayBufferView> ValueDeserializer::ReadJSArrayBufferView(
} }
Handle<JSTypedArray> typed_array = isolate_->factory()->NewJSTypedArray( Handle<JSTypedArray> typed_array = isolate_->factory()->NewJSTypedArray(
external_array_type, buffer, byte_offset, byte_length / element_size); external_array_type, buffer, byte_offset, byte_length / element_size);
typed_array->set_bit_field(flags); if (!ValidateAndSetJSArrayBufferViewFlags(*typed_array, *buffer, flags)) {
return MaybeHandle<JSArrayBufferView>();
}
AddObjectWithID(id, typed_array); AddObjectWithID(id, typed_array);
return typed_array; return typed_array;
} }
bool ValueDeserializer::ValidateAndSetJSArrayBufferViewFlags(
JSArrayBufferView view, JSArrayBuffer buffer, uint32_t serialized_flags) {
bool is_length_tracking =
JSArrayBufferViewIsLengthTracking::decode(serialized_flags);
bool is_backed_by_rab =
JSArrayBufferViewIsBackedByRab::decode(serialized_flags);
// TODO(marja): When the version number is bumped the next time, check that
// serialized_flags doesn't contain spurious 1-bits.
if (is_backed_by_rab || is_length_tracking) {
if (!FLAG_harmony_rab_gsab) {
return false;
}
if (!buffer.is_resizable()) {
return false;
}
if (is_backed_by_rab && buffer.is_shared()) {
return false;
}
}
view.set_is_length_tracking(is_length_tracking);
view.set_is_backed_by_rab(is_backed_by_rab);
return true;
}
MaybeHandle<Object> ValueDeserializer::ReadJSError() { MaybeHandle<Object> ValueDeserializer::ReadJSError() {
uint32_t id = next_id_++; uint32_t id = next_id_++;
......
...@@ -300,6 +300,9 @@ class ValueDeserializer { ...@@ -300,6 +300,9 @@ class ValueDeserializer {
V8_WARN_UNUSED_RESULT; V8_WARN_UNUSED_RESULT;
MaybeHandle<JSArrayBufferView> ReadJSArrayBufferView( MaybeHandle<JSArrayBufferView> ReadJSArrayBufferView(
Handle<JSArrayBuffer> buffer) V8_WARN_UNUSED_RESULT; Handle<JSArrayBuffer> buffer) V8_WARN_UNUSED_RESULT;
bool ValidateAndSetJSArrayBufferViewFlags(
JSArrayBufferView view, JSArrayBuffer buffer,
uint32_t serialized_flags) V8_WARN_UNUSED_RESULT;
MaybeHandle<Object> ReadJSError() V8_WARN_UNUSED_RESULT; MaybeHandle<Object> ReadJSError() V8_WARN_UNUSED_RESULT;
#if V8_ENABLE_WEBASSEMBLY #if V8_ENABLE_WEBASSEMBLY
MaybeHandle<JSObject> ReadWasmModuleTransfer() V8_WARN_UNUSED_RESULT; MaybeHandle<JSObject> ReadWasmModuleTransfer() V8_WARN_UNUSED_RESULT;
......
// Copyright 2022 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-rab-gsab
"use strict";
(function FlagMismatch() {
// Length tracking TA, buffer not resizable.
const data1 = new Uint8Array([255, 15, 66, 4, 3, 5, 7, 11, 86, 66, 1, 2, 1]);
assertThrows(() => { d8.serializer.deserialize(data1.buffer); });
// RAB backed TA, buffer not resizable.
const data2 = new Uint8Array([255, 15, 66, 4, 3, 5, 7, 11, 86, 66, 1, 2, 2]);
assertThrows(() => { d8.serializer.deserialize(data2.buffer); });
})();
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