diff --git a/src/builtins/array-join.tq b/src/builtins/array-join.tq index c61dd6c830..5340d37327 100644 --- a/src/builtins/array-join.tq +++ b/src/builtins/array-join.tq @@ -495,6 +495,10 @@ module array { // 2. Let len be ? ToLength(? Get(O, "length")). const len: Number = GetLengthProperty(o); + // Only handle valid array lengths. Although the spec allows larger values, + // this matches historical V8 behavior. + if (len > kMaxArrayIndex + 1) ThrowTypeError(context, kInvalidArrayLength); + // 3. If separator is undefined, let sep be the single-element String ",". // 4. Else, let sep be ? ToString(separator). let sep: String = diff --git a/src/builtins/base.tq b/src/builtins/base.tq index f7402d36ae..7d17a25040 100644 --- a/src/builtins/base.tq +++ b/src/builtins/base.tq @@ -175,6 +175,8 @@ const kIteratorValueNotAnObject: constexpr MessageTemplate const kNotIterable: constexpr MessageTemplate generates 'MessageTemplate::kNotIterable'; +const kMaxArrayIndex: + constexpr uint32 generates 'JSArray::kMaxArrayIndex'; const kMaxSafeInteger: constexpr float64 generates 'kMaxSafeInteger'; const kStringMaxLength: constexpr int31 generates 'String::kMaxLength'; const kFixedArrayMaxLength: @@ -402,6 +404,8 @@ extern operator '&' macro WordAnd(uintptr, uintptr): uintptr; extern operator '|' macro WordOr(uintptr, uintptr): uintptr; extern operator '+' macro Int32Add(int32, int32): int32; +extern operator '+' macro ConstexprUint32Add( + constexpr uint32, constexpr int32): constexpr uint32; extern operator '-' macro Int32Sub(int32, int32): int32; extern operator '*' macro Int32Mul(int32, int32): int32; extern operator '%' macro Int32Mod(int32, int32): int32; @@ -573,6 +577,7 @@ extern macro ChangeNonnegativeNumberToUintPtr(Number): uintptr; extern macro NumberConstant(constexpr float64): Number; extern macro NumberConstant(constexpr int32): Number; +extern macro NumberConstant(constexpr uint32): Number; extern macro IntPtrConstant(constexpr int31): intptr; extern macro IntPtrConstant(constexpr int32): intptr; extern macro Int32Constant(constexpr int31): int31; @@ -610,6 +615,10 @@ FromConstexpr(i: constexpr int31): Number { FromConstexpr(i: constexpr int31): float64 { return Float64Constant(i); } +macro FromConstexpr(o: constexpr uint32): A; +FromConstexpr(i: constexpr uint32): Number { + return NumberConstant(i); +} macro FromConstexpr(o: constexpr int32): A; FromConstexpr(i: constexpr int32): intptr { return IntPtrConstant(i); diff --git a/src/code-stub-assembler.h b/src/code-stub-assembler.h index bb585cb2b0..b0daea42ab 100644 --- a/src/code-stub-assembler.h +++ b/src/code-stub-assembler.h @@ -3142,6 +3142,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler { bool ConstexprBoolNot(bool value) { return !value; } bool ConstexprInt31Equal(int31_t a, int31_t b) { return a == b; } + uint32_t ConstexprUint32Add(uint32_t a, uint32_t b) { return a + b; } void PerformStackCheck(TNode context); diff --git a/test/mjsunit/regress/regress-crbug-902672.js b/test/mjsunit/regress/regress-crbug-902672.js new file mode 100644 index 0000000000..4073b554e9 --- /dev/null +++ b/test/mjsunit/regress/regress-crbug-902672.js @@ -0,0 +1,8 @@ +// Copyright 2018 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. + +var a = this; +var b = {}; +a.length = 4294967296; // 2 ^ 32 (max array length + 1) +assertThrows(() => Array.prototype.join.call(a,b), TypeError);