Array.prototype.sort: Unchecked calls to hasOwnProperty and push and sort

BUG=v8:3537
LOG=
R=arv@chromium.org, wingo@igalia.com, yangguo@chromium.org

Review URL: https://codereview.chromium.org/555173002

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24005 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
wingo@igalia.com 2014-09-17 14:01:25 +00:00
parent 6cbeb6d00e
commit 00375fba59
3 changed files with 57 additions and 11 deletions

View File

@ -863,11 +863,12 @@ function ArraySort(comparefn) {
var t_array = [];
// Use both 'from' and 'to' to determine the pivot candidates.
var increment = 200 + ((to - from) & 15);
for (var i = from + 1; i < to - 1; i += increment) {
t_array.push([i, a[i]]);
for (var i = from + 1, j = 0; i < to - 1; i += increment, j++) {
t_array[j] = [i, a[i]];
}
t_array.sort(function(a, b) {
return %_CallFunction(receiver, a[1], b[1], comparefn) } );
%_CallFunction(t_array, function(a, b) {
return %_CallFunction(receiver, a[1], b[1], comparefn);
}, ArraySort);
var third_index = t_array[t_array.length >> 1][0];
return third_index;
}
@ -969,7 +970,7 @@ function ArraySort(comparefn) {
// It's an interval.
var proto_length = indices;
for (var i = 0; i < proto_length; i++) {
if (!obj.hasOwnProperty(i) && proto.hasOwnProperty(i)) {
if (!HAS_OWN_PROPERTY(obj, i) && HAS_OWN_PROPERTY(proto, i)) {
obj[i] = proto[i];
if (i >= max) { max = i + 1; }
}
@ -977,8 +978,8 @@ function ArraySort(comparefn) {
} else {
for (var i = 0; i < indices.length; i++) {
var index = indices[i];
if (!IS_UNDEFINED(index) &&
!obj.hasOwnProperty(index) && proto.hasOwnProperty(index)) {
if (!IS_UNDEFINED(index) && !HAS_OWN_PROPERTY(obj, index)
&& HAS_OWN_PROPERTY(proto, index)) {
obj[index] = proto[index];
if (index >= max) { max = index + 1; }
}
@ -998,7 +999,7 @@ function ArraySort(comparefn) {
// It's an interval.
var proto_length = indices;
for (var i = from; i < proto_length; i++) {
if (proto.hasOwnProperty(i)) {
if (HAS_OWN_PROPERTY(proto, i)) {
obj[i] = UNDEFINED;
}
}
@ -1006,7 +1007,7 @@ function ArraySort(comparefn) {
for (var i = 0; i < indices.length; i++) {
var index = indices[i];
if (!IS_UNDEFINED(index) && from <= index &&
proto.hasOwnProperty(index)) {
HAS_OWN_PROPERTY(proto, index)) {
obj[index] = UNDEFINED;
}
}
@ -1029,14 +1030,14 @@ function ArraySort(comparefn) {
}
// Maintain the invariant num_holes = the number of holes in the original
// array with indices <= first_undefined or > last_defined.
if (!obj.hasOwnProperty(first_undefined)) {
if (!HAS_OWN_PROPERTY(obj, first_undefined)) {
num_holes++;
}
// Find last defined element.
while (first_undefined < last_defined &&
IS_UNDEFINED(obj[last_defined])) {
if (!obj.hasOwnProperty(last_defined)) {
if (!HAS_OWN_PROPERTY(obj, last_defined)) {
num_holes++;
}
last_defined--;

View File

@ -166,6 +166,7 @@ macro TO_STRING_INLINE(arg) = (IS_STRING(%IS_VAR(arg)) ? arg : NonStringToString
macro TO_NUMBER_INLINE(arg) = (IS_NUMBER(%IS_VAR(arg)) ? arg : NonNumberToNumber(arg));
macro TO_OBJECT_INLINE(arg) = (IS_SPEC_OBJECT(%IS_VAR(arg)) ? arg : ToObject(arg));
macro JSON_NUMBER_TO_STRING(arg) = ((%_IsSmi(%IS_VAR(arg)) || arg - arg == 0) ? %_NumberToString(arg) : "null");
macro HAS_OWN_PROPERTY(obj, index) = (%_CallFunction(obj, index, ObjectHasOwnProperty));
# Private names.
# GET_PRIVATE should only be used if the property is known to exists on obj

View File

@ -404,3 +404,47 @@ function cmpTest(a, b) {
return a.val - b.val;
}
arr.sort(cmpTest);
function TestSortDoesNotDependOnObjectPrototypeHasOwnProperty() {
Array.prototype.sort.call({
__proto__: { hasOwnProperty: null, 0: 1 },
length: 5
});
var arr = new Array(2);
Object.defineProperty(arr, 0, { get: function() {}, set: function() {} });
arr.hasOwnProperty = null;
arr.sort();
}
TestSortDoesNotDependOnObjectPrototypeHasOwnProperty();
function TestSortDoesNotDependOnArrayPrototypePush() {
// InsertionSort is used for arrays which length <= 22
var arr = [];
for (var i = 0; i < 22; i++) arr[i] = {};
Array.prototype.push = function() {
fail('Should not call push');
};
arr.sort();
// Quicksort is used for arrays which length > 22
// Arrays which length > 1000 guarantee GetThirdIndex is executed
arr = [];
for (var i = 0; i < 2000; ++i) arr[i] = {};
arr.sort();
}
TestSortDoesNotDependOnArrayPrototypePush();
function TestSortDoesNotDependOnArrayPrototypeSort() {
var arr = [];
for (var i = 0; i < 2000; i++) arr[i] = {};
var sortfn = Array.prototype.sort;
Array.prototype.sort = function() {
fail('Should not call sort');
};
sortfn.call(arr);
}
TestSortDoesNotDependOnArrayPrototypeSort();