diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e16783f7689..65e990f2f18f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,7 @@ ## Changelog +##### Unreleased +- Prevented a possible almost infinite loop in non-standard implementations of some backward iteration array methods + ##### 3.6.3 - 2020.01.11 - Fixed replacement of substitutes of undefined capture groups in `.replace` in Safari 13.0-, [#471](https://github.com/zloirock/core-js/issues/471), [#745](https://github.com/zloirock/core-js/issues/745), thanks [@mattclough1](https://github.com/mattclough1) - Improved compat data for old engines diff --git a/packages/core-js/internals/array-last-index-of.js b/packages/core-js/internals/array-last-index-of.js index 69e38a491a86..8d1c93c4a9ff 100644 --- a/packages/core-js/internals/array-last-index-of.js +++ b/packages/core-js/internals/array-last-index-of.js @@ -9,7 +9,8 @@ var min = Math.min; var nativeLastIndexOf = [].lastIndexOf; var NEGATIVE_ZERO = !!nativeLastIndexOf && 1 / [1].lastIndexOf(1, -0) < 0; var STRICT_METHOD = arrayMethodIsStrict('lastIndexOf'); -var USES_TO_LENGTH = arrayMethodUsesToLength('lastIndexOf', { ACCESSORS: true, 1: 2147483647 }); +// For preventing possible almost infinite loop in non-standard implementations, test the forward version of the method +var USES_TO_LENGTH = arrayMethodUsesToLength('indexOf', { ACCESSORS: true, 1: 0 }); var FORCED = NEGATIVE_ZERO || !STRICT_METHOD || !USES_TO_LENGTH; // `Array.prototype.lastIndexOf` method implementation diff --git a/packages/core-js/internals/array-method-uses-to-length.js b/packages/core-js/internals/array-method-uses-to-length.js index b55d1f14a60b..9863b6f4c004 100644 --- a/packages/core-js/internals/array-method-uses-to-length.js +++ b/packages/core-js/internals/array-method-uses-to-length.js @@ -3,28 +3,25 @@ var fails = require('../internals/fails'); var has = require('../internals/has'); var defineProperty = Object.defineProperty; +var cache = {}; var thrower = function (it) { throw it; }; module.exports = function (METHOD_NAME, options) { + if (has(cache, METHOD_NAME)) return cache[METHOD_NAME]; if (!options) options = {}; var method = [][METHOD_NAME]; var ACCESSORS = has(options, 'ACCESSORS') ? options.ACCESSORS : false; var argument0 = has(options, 0) ? options[0] : thrower; var argument1 = has(options, 1) ? options[1] : undefined; - return !!method && !fails(function () { + return cache[METHOD_NAME] = !!method && !fails(function () { if (ACCESSORS && !DESCRIPTORS) return true; var O = { length: -1 }; - var addTrap = function (key) { - if (ACCESSORS) defineProperty(O, key, { enumerable: true, get: thrower }); - else O[key] = 1; - }; + if (ACCESSORS) defineProperty(O, 1, { enumerable: true, get: thrower }); + else O[1] = 1; - addTrap(1); - addTrap(2147483646); - addTrap(4294967294); method.call(O, argument0, argument1); }); }; diff --git a/packages/core-js/modules/es.array.reduce-right.js b/packages/core-js/modules/es.array.reduce-right.js index d044bc9603ca..37aeb2d315ef 100644 --- a/packages/core-js/modules/es.array.reduce-right.js +++ b/packages/core-js/modules/es.array.reduce-right.js @@ -5,7 +5,8 @@ var arrayMethodIsStrict = require('../internals/array-method-is-strict'); var arrayMethodUsesToLength = require('../internals/array-method-uses-to-length'); var STRICT_METHOD = arrayMethodIsStrict('reduceRight'); -var USES_TO_LENGTH = arrayMethodUsesToLength('reduceRight', { 1: 0 }); +// For preventing possible almost infinite loop in non-standard implementations, test the forward version of the method +var USES_TO_LENGTH = arrayMethodUsesToLength('reduce', { 1: 0 }); // `Array.prototype.reduceRight` method // https://tc39.github.io/ecma262/#sec-array.prototype.reduceright diff --git a/tests/compat/tests.js b/tests/compat/tests.js index 3b30fae1ced4..40e081757e39 100644 --- a/tests/compat/tests.js +++ b/tests/compat/tests.js @@ -321,16 +321,10 @@ GLOBAL.tests = { return true; }, 'es.array.last-index-of': function () { - [].lastIndexOf.call(Object.defineProperties({ length: -1 }, { - 2147483646: { - enumerable: true, - get: function (it) { throw it; } - }, - 4294967294: { - enumerable: true, - get: function (it) { throw it; } - } - }), 2147483647); + [].indexOf.call(Object.defineProperty({ length: -1 }, 0, { + enumerable: true, + get: function (it) { throw it; } + }), 0); try { [].lastIndexOf.call(null); } catch (error) { @@ -359,7 +353,7 @@ GLOBAL.tests = { } }, 'es.array.reduce-right': function () { - [].reduceRight.call({ length: -1, 2147483646: 1, 4294967294: 1 }, function (it) { throw it; }, 1); + [].reduce.call({ length: -1, 0: 1 }, function (it) { throw it; }, 0); try { Array.prototype.reduceRight.call(null, function () { /* empty */ }, 1); } catch (error) {