Commit 82f6179c authored by Simon Zünd's avatar Simon Zünd Committed by Commit Bot

[array] Prevent negative work array capacity when sorting

When allocating large arrays on 32-bit systems, the length conversion
caused the work array capacity to become negative. As the sort range
is currently clamped at kSmiMaxValue anyway, the fix is to also
clamp the work capacity to that value.

R=jgruber@chromium.org

Bug: chromium:967065
Change-Id: I9ea60464c5b7f3796c5389cbaf668b990eddecf6
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1630672
Auto-Submit: Simon Zünd <szuend@chromium.org>
Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Commit-Queue: Simon Zünd <szuend@chromium.org>
Cr-Commit-Position: refs/heads/master@{#61845}
parent 5b27fd5d
// Copyright 2019 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.
// Tests that the receiver {length} property conversion works on 32-bit
// systems (i.e. it should not crash).
function ThrowingSort() {
const __v_3 = new Array(2147549152);
Object.defineProperty(__v_3, 0, {
get: () => { throw new Error("Do not actually sort!"); }
});
__v_3.sort();
}
assertThrows(() => ThrowingSort());
......@@ -99,6 +99,38 @@ namespace array {
type FastSmiElements;
type FastObjectElements;
// With the pre-processing step in Torque, the exact number of elements
// to sort is unknown at the time the sort state is created.
// The 'length' property is an upper bound (as per spec),
// while the actual size of the backing store is a good guess.
// After the pre-processing step, the workarray won't change in length.
macro CalculateWorkArrayLength(
receiver: JSReceiver, initialReceiverLength: Number): intptr {
// TODO(szuend): Implement full range sorting, not only up to MaxSmi.
// https://crbug.com/v8/7970.
let clampedReceiverLength: uintptr =
Convert<uintptr>(initialReceiverLength);
if (clampedReceiverLength > kSmiMaxValue) {
clampedReceiverLength = kSmiMaxValue;
}
let workArrayLength: intptr = Convert<intptr>(clampedReceiverLength);
try {
const object = Cast<JSObject>(receiver) otherwise NoJsObject;
const elementsLength = Convert<intptr>(object.elements.length);
// In some cases, elements are only on prototypes, but not on the receiver
// itself. Do nothing then, as {workArrayLength} got initialized with the
// {length} property.
if (elementsLength != 0) {
workArrayLength = IntPtrMin(workArrayLength, elementsLength);
}
}
label NoJsObject {}
return workArrayLength;
}
transitioning macro NewSortState(implicit context: Context)(
receiver: JSReceiver, comparefn: Undefined | Callable,
initialReceiverLength: Number): SortState {
......@@ -142,24 +174,8 @@ namespace array {
canUseSameAccessorFn = CanUseSameAccessor<GenericElementsAccessor>;
}
// With the pre-processing step in Torque, the exact number of elements
// to sort is unknown at this time. The 'length' property is an upper bound
// (as per spec) while the actual size of the backing store is a good guess.
// After the pre-processing step, the workarray won't change in length.
let workArrayLength: intptr =
Signed(Convert<uintptr>(initialReceiverLength));
try {
const object = Cast<JSObject>(receiver) otherwise NoJsObject;
const elementsLength = Convert<intptr>(object.elements.length);
// In some cases, elements are only on prototypes, but not on the receiver
// itself. Do nothing then, as {workArrayLength} got initialized with the
// {length} property.
if (elementsLength != 0) {
workArrayLength = IntPtrMin(workArrayLength, elementsLength);
}
}
label NoJsObject {}
const workArrayLength =
CalculateWorkArrayLength(receiver, initialReceiverLength);
return new SortState{
receiver,
......
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