Check length in Array.prototype.concat.

Throw a TypeError if the length of a concat-spreadable object makes the
total length too large, as specified.

Bug: v8:7652
Change-Id: Ie3f694d64c949703edd733c0310cfb3f64b78a15
Reviewed-on: https://chromium-review.googlesource.com/1013714
Reviewed-by: Benedikt Meurer <bmeurer@chromium.org>
Commit-Queue: Georg Neis <neis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#52644}
This commit is contained in:
Georg Neis 2018-04-17 14:01:32 +02:00 committed by Commit Bot
parent c3da929020
commit 92cde630df
2 changed files with 28 additions and 9 deletions

View File

@ -377,6 +377,8 @@ class ArrayConcatVisitor {
return true;
}
uint32_t index_offset() const { return index_offset_; }
void increase_index_offset(uint32_t delta) {
if (JSObject::kMaxElementCount - index_offset_ < delta) {
index_offset_ = JSObject::kMaxElementCount;
@ -709,6 +711,11 @@ bool IterateElements(Isolate* isolate, Handle<JSReceiver> receiver,
Handle<Object> val;
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate, val, Object::GetLengthFromArrayLike(isolate, receiver), false);
if (visitor->index_offset() + val->Number() > kMaxSafeInteger) {
isolate->Throw(*isolate->factory()->NewTypeError(
MessageTemplate::kInvalidArrayLength));
return false;
}
// TODO(caitp): Support larger element indexes (up to 2^53-1).
if (!val->ToUint32(&length)) {
length = 0;

View File

@ -2,13 +2,25 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
let a = {length: 2**53 - 1};
const unshift = Array.prototype.unshift;
assertThrows(() => unshift.call(a, 42), TypeError);
assertEquals(unshift.call(a), 2**53 - 1);
const splice = Array.prototype.splice;
assertThrows(() => splice.call(a, 0, 0, 42), TypeError);
assertEquals(splice.call(a, 0, 1, 42).length, 1);
assertEquals(a[0], 42);
const unshift = Array.prototype.unshift;
{
let a = {length: 2**53 - 1};
assertThrows(() => unshift.call(a, 42), TypeError);
assertEquals(unshift.call(a), 2**53 - 1);
}
{
let a = {length: 2**53 - 1};
assertThrows(() => splice.call(a, 0, 0, 42), TypeError);
assertEquals(splice.call(a, 0, 1, 42).length, 1);
assertEquals(a[0], 42);
}
{
let a = {length: 2**53 - 1, [Symbol.isConcatSpreadable]: true};
assertThrows(() => [42].concat(a), TypeError);
assertThrows(() => [, ].concat(a), TypeError);
assertThrows(() => [].concat(42, a), TypeError);
}