[rab/gsab] Fix JSTypedArray::Validate to throw for oob rab/gsab

This will change the behavior of %TypedArray%.prototype.fill.

Bug: v8:11111
Change-Id: I66e7d3decf07663a6497c3c86374b3c77ab6a682
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3056977
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Commit-Queue: Marja Hölttä <marja@chromium.org>
Cr-Commit-Position: refs/heads/master@{#75988}
This commit is contained in:
Marja Hölttä 2021-07-28 13:04:32 +02:00 committed by V8 LUCI CQ
parent bce81d6be0
commit df45384de4
3 changed files with 27 additions and 6 deletions

View File

@ -200,17 +200,20 @@ bool JSTypedArray::IsVariableLength() const {
return is_length_tracking() || is_backed_by_rab();
}
size_t JSTypedArray::GetLength() const {
size_t JSTypedArray::GetLengthOrOutOfBounds(bool& out_of_bounds) const {
DCHECK(!out_of_bounds);
if (WasDetached()) return 0;
if (is_length_tracking()) {
if (is_backed_by_rab()) {
if (byte_offset() >= buffer().byte_length()) {
out_of_bounds = true;
return 0;
}
return (buffer().byte_length() - byte_offset()) / element_size();
}
if (byte_offset() >=
buffer().GetBackingStore()->byte_length(std::memory_order_seq_cst)) {
out_of_bounds = true;
return 0;
}
return (buffer().GetBackingStore()->byte_length(std::memory_order_seq_cst) -
@ -223,12 +226,18 @@ size_t JSTypedArray::GetLength() const {
// JSTypedArray.
if (byte_offset() + array_length * element_size() >
buffer().byte_length()) {
out_of_bounds = true;
return 0;
}
}
return array_length;
}
size_t JSTypedArray::GetLength() const {
bool out_of_bounds = false;
return GetLengthOrOutOfBounds(out_of_bounds);
}
void JSTypedArray::AllocateExternalPointerEntries(Isolate* isolate) {
InitExternalPointerField(kExternalPointerOffset, isolate);
}
@ -364,6 +373,17 @@ MaybeHandle<JSTypedArray> JSTypedArray::Validate(Isolate* isolate,
THROW_NEW_ERROR(isolate, NewTypeError(message, operation), JSTypedArray);
}
if (V8_UNLIKELY(array->IsVariableLength())) {
bool out_of_bounds = false;
array->GetLengthOrOutOfBounds(out_of_bounds);
if (out_of_bounds) {
const MessageTemplate message = MessageTemplate::kDetachedOperation;
Handle<String> operation =
isolate->factory()->NewStringFromAsciiChecked(method_name);
THROW_NEW_ERROR(isolate, NewTypeError(message, operation), JSTypedArray);
}
}
// spec describes to return `buffer`, but it may disrupt current
// implementations, and it's much useful to return array for now.
return array;

View File

@ -307,6 +307,7 @@ class JSTypedArray
DECL_BOOLEAN_ACCESSORS(is_length_tracking)
DECL_BOOLEAN_ACCESSORS(is_backed_by_rab)
inline bool IsVariableLength() const;
inline size_t GetLengthOrOutOfBounds(bool& out_of_bounds) const;
inline size_t GetLength() const;
static size_t LengthTrackingGsabBackedTypedArrayLength(Isolate* isolate,

View File

@ -996,10 +996,10 @@ function TestIterationAndResize(ta, expected, rab, resize_after,
// Shrink so that fixed length TAs go out of bounds.
rab.resize(3 * ctor.BYTES_PER_ELEMENT);
FillHelper(fixedLength, 5);
assertThrows(() => FillHelper(fixedLength, 5), TypeError);
assertEquals([3, 3, 4], ReadDataFromBuffer(rab, ctor));
FillHelper(fixedLengthWithOffset, 6);
assertThrows(() => FillHelper(fixedLengthWithOffset, 6), TypeError);
assertEquals([3, 3, 4], ReadDataFromBuffer(rab, ctor));
FillHelper(lengthTracking, 7);
@ -1011,16 +1011,16 @@ function TestIterationAndResize(ta, expected, rab, resize_after,
// Shrink so that the TAs with offset go out of bounds.
rab.resize(1 * ctor.BYTES_PER_ELEMENT);
FillHelper(fixedLength, 9);
assertThrows(() => FillHelper(fixedLength, 9), TypeError);
assertEquals([7], ReadDataFromBuffer(rab, ctor));
FillHelper(fixedLengthWithOffset, 10);
assertThrows(() => FillHelper(fixedLengthWithOffset, 10), TypeError);
assertEquals([7], ReadDataFromBuffer(rab, ctor));
FillHelper(lengthTracking, 11);
assertEquals([11], ReadDataFromBuffer(rab, ctor));
FillHelper(lengthTrackingWithOffset, 12);
assertThrows(() => FillHelper(lengthTrackingWithOffset, 12), TypeError);
assertEquals([11], ReadDataFromBuffer(rab, ctor));
// Grow so that all TAs are back in-bounds.