Skip to content

Commit

Permalink
add a fix of a V8 ~ Chrome 36- Object.defineProperty bug
Browse files Browse the repository at this point in the history
  • Loading branch information
zloirock committed Dec 25, 2021
1 parent 6ce4404 commit 901d97b
Show file tree
Hide file tree
Showing 17 changed files with 99 additions and 18 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
@@ -1,6 +1,6 @@
## Changelog
##### Unreleased
- Nothing
- Added a fix of [a V8 ~ Chrome 36- `Object.defineProperty` bug](https://bugs.chromium.org/p/v8/issues/detail?id=3334), [Babel issue](https://github.com/babel/babel/issues/14056)

##### 3.20.1 - 2021.12.23
- Fixed the order of calling reactions of already fulfilled / rejected promises in `Promise.prototype.then`, [#1026](https://github.com/zloirock/core-js/issues/1026)
Expand Down
4 changes: 2 additions & 2 deletions packages/core-js-compat/src/data.mjs
Expand Up @@ -678,15 +678,15 @@ export const data = {
rhino: '1.7.13',
},
'es.object.define-properties': {
chrome: '5',
chrome: '37',
firefox: '4',
ie: '9',
opera: '12',
safari: '5.1',
rhino: '1.7.13',
},
'es.object.define-property': {
chrome: '5',
chrome: '37',
firefox: '4',
ie: '9',
opera: '12',
Expand Down
2 changes: 1 addition & 1 deletion packages/core-js/internals/numeric-range-iterator.js
Expand Up @@ -3,7 +3,7 @@ var global = require('../internals/global');
var InternalStateModule = require('../internals/internal-state');
var createIteratorConstructor = require('../internals/create-iterator-constructor');
var isObject = require('../internals/is-object');
var defineProperties = require('../internals/object-define-properties');
var defineProperties = require('../internals/object-define-properties').f;
var DESCRIPTORS = require('../internals/descriptors');

var INCORRECT_RANGE = 'Incorrect Number.range arguments';
Expand Down
4 changes: 2 additions & 2 deletions packages/core-js/internals/object-create.js
@@ -1,6 +1,6 @@
/* global ActiveXObject -- old IE, WSH */
var anObject = require('../internals/an-object');
var defineProperties = require('../internals/object-define-properties');
var definePropertiesModule = require('../internals/object-define-properties');
var enumBugKeys = require('../internals/enum-bug-keys');
var hiddenKeys = require('../internals/hidden-keys');
var html = require('../internals/html');
Expand Down Expand Up @@ -78,5 +78,5 @@ module.exports = Object.create || function create(O, Properties) {
// add "__proto__" for Object.getPrototypeOf polyfill
result[IE_PROTO] = O;
} else result = NullProtoObject();
return Properties === undefined ? result : defineProperties(result, Properties);
return Properties === undefined ? result : definePropertiesModule.f(result, Properties);
};
3 changes: 2 additions & 1 deletion packages/core-js/internals/object-define-properties.js
@@ -1,4 +1,5 @@
var DESCRIPTORS = require('../internals/descriptors');
var V8_PROTOTYPE_DEFINE_BUG = require('../internals/v8-prototype-define-bug');
var definePropertyModule = require('../internals/object-define-property');
var anObject = require('../internals/an-object');
var toIndexedObject = require('../internals/to-indexed-object');
Expand All @@ -7,7 +8,7 @@ var objectKeys = require('../internals/object-keys');
// `Object.defineProperties` method
// https://tc39.es/ecma262/#sec-object.defineproperties
// eslint-disable-next-line es/no-object-defineproperties -- safe
module.exports = DESCRIPTORS ? Object.defineProperties : function defineProperties(O, Properties) {
exports.f = DESCRIPTORS && !V8_PROTOTYPE_DEFINE_BUG ? Object.defineProperties : function defineProperties(O, Properties) {
anObject(O);
var props = toIndexedObject(Properties);
var keys = objectKeys(Properties);
Expand Down
23 changes: 22 additions & 1 deletion packages/core-js/internals/object-define-property.js
@@ -1,16 +1,37 @@
var global = require('../internals/global');
var DESCRIPTORS = require('../internals/descriptors');
var IE8_DOM_DEFINE = require('../internals/ie8-dom-define');
var V8_PROTOTYPE_DEFINE_BUG = require('../internals/v8-prototype-define-bug');
var anObject = require('../internals/an-object');
var toPropertyKey = require('../internals/to-property-key');

var TypeError = global.TypeError;
// eslint-disable-next-line es/no-object-defineproperty -- safe
var $defineProperty = Object.defineProperty;
// eslint-disable-next-line es/no-object-getownpropertydescriptor -- safe
var $getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
var ENUMERABLE = 'enumerable';
var CONFIGURABLE = 'configurable';
var WRITABLE = 'writable';

// `Object.defineProperty` method
// https://tc39.es/ecma262/#sec-object.defineproperty
exports.f = DESCRIPTORS ? $defineProperty : function defineProperty(O, P, Attributes) {
exports.f = DESCRIPTORS ? V8_PROTOTYPE_DEFINE_BUG ? function defineProperty(O, P, Attributes) {
anObject(O);
P = toPropertyKey(P);
anObject(Attributes);
if (typeof O === 'function' && P === 'prototype' && 'value' in Attributes && WRITABLE in Attributes && !Attributes[WRITABLE]) {
var current = $getOwnPropertyDescriptor(O, P);
if (current && current[WRITABLE]) {
O[P] = Attributes.value;
Attributes = {
configurable: CONFIGURABLE in Attributes ? Attributes[CONFIGURABLE] : current[CONFIGURABLE],
enumerable: ENUMERABLE in Attributes ? Attributes[ENUMERABLE] : current[ENUMERABLE],
writable: false
};
}
} return $defineProperty(O, P, Attributes);
} : $defineProperty : function defineProperty(O, P, Attributes) {
anObject(O);
P = toPropertyKey(P);
anObject(Attributes);
Expand Down
12 changes: 12 additions & 0 deletions packages/core-js/internals/v8-prototype-define-bug.js
@@ -0,0 +1,12 @@
var DESCRIPTORS = require('../internals/descriptors');
var fails = require('../internals/fails');

// V8 ~ Chrome 36-
// https://bugs.chromium.org/p/v8/issues/detail?id=3334
module.exports = DESCRIPTORS && fails(function () {
// eslint-disable-next-line es/no-object-defineproperty -- required for testing
return Object.defineProperty(function () { /* empty */ }, 'prototype', {
value: 42,
writable: false
}).prototype != 42;
});
5 changes: 3 additions & 2 deletions packages/core-js/modules/es.object.define-properties.js
@@ -1,9 +1,10 @@
var $ = require('../internals/export');
var DESCRIPTORS = require('../internals/descriptors');
var defineProperties = require('../internals/object-define-properties');
var defineProperties = require('../internals/object-define-properties').f;

// `Object.defineProperties` method
// https://tc39.es/ecma262/#sec-object.defineproperties
$({ target: 'Object', stat: true, forced: !DESCRIPTORS, sham: !DESCRIPTORS }, {
// eslint-disable-next-line es/no-object-defineproperties -- safe
$({ target: 'Object', stat: true, forced: Object.defineProperties !== defineProperties, sham: !DESCRIPTORS }, {
defineProperties: defineProperties
});
7 changes: 4 additions & 3 deletions packages/core-js/modules/es.object.define-property.js
@@ -1,9 +1,10 @@
var $ = require('../internals/export');
var DESCRIPTORS = require('../internals/descriptors');
var objectDefinePropertyModule = require('../internals/object-define-property');
var defineProperty = require('../internals/object-define-property').f;

// `Object.defineProperty` method
// https://tc39.es/ecma262/#sec-object.defineproperty
$({ target: 'Object', stat: true, forced: !DESCRIPTORS, sham: !DESCRIPTORS }, {
defineProperty: objectDefinePropertyModule.f
// eslint-disable-next-line es/no-object-defineproperty -- safe
$({ target: 'Object', stat: true, forced: Object.defineProperty !== defineProperty, sham: !DESCRIPTORS }, {
defineProperty: defineProperty
});
2 changes: 2 additions & 0 deletions packages/core-js/modules/es.symbol.js
Expand Up @@ -28,6 +28,7 @@ var getOwnPropertyNamesExternal = require('../internals/object-get-own-property-
var getOwnPropertySymbolsModule = require('../internals/object-get-own-property-symbols');
var getOwnPropertyDescriptorModule = require('../internals/object-get-own-property-descriptor');
var definePropertyModule = require('../internals/object-define-property');
var definePropertiesModule = require('../internals/object-define-properties');
var propertyIsEnumerableModule = require('../internals/object-property-is-enumerable');
var arraySlice = require('../internals/array-slice');
var redefine = require('../internals/redefine');
Expand Down Expand Up @@ -194,6 +195,7 @@ if (!NATIVE_SYMBOL) {

propertyIsEnumerableModule.f = $propertyIsEnumerable;
definePropertyModule.f = $defineProperty;
definePropertiesModule.f = $defineProperties;
getOwnPropertyDescriptorModule.f = $getOwnPropertyDescriptor;
getOwnPropertyNamesModule.f = getOwnPropertyNamesExternal.f = $getOwnPropertyNames;
getOwnPropertySymbolsModule.f = $getOwnPropertySymbols;
Expand Down
2 changes: 1 addition & 1 deletion packages/core-js/modules/web.dom-exception.constructor.js
Expand Up @@ -6,7 +6,7 @@ var fails = require('../internals/fails');
var create = require('../internals/object-create');
var createPropertyDescriptor = require('../internals/create-property-descriptor');
var defineProperty = require('../internals/object-define-property').f;
var defineProperties = require('../internals/object-define-properties');
var defineProperties = require('../internals/object-define-properties').f;
var redefine = require('../internals/redefine');
var hasOwn = require('../internals/has-own-property');
var anInstance = require('../internals/an-instance');
Expand Down
2 changes: 1 addition & 1 deletion packages/core-js/modules/web.url.js
Expand Up @@ -7,7 +7,7 @@ var USE_NATIVE_URL = require('../internals/native-url');
var global = require('../internals/global');
var bind = require('../internals/function-bind-context');
var uncurryThis = require('../internals/function-uncurry-this');
var defineProperties = require('../internals/object-define-properties');
var defineProperties = require('../internals/object-define-properties').f;
var redefine = require('../internals/redefine');
var anInstance = require('../internals/an-instance');
var hasOwn = require('../internals/has-own-property');
Expand Down
15 changes: 12 additions & 3 deletions tests/compat/tests.js
Expand Up @@ -36,7 +36,16 @@ var IS_NODE = Object.prototype.toString.call(process) == '[object process]';
var WEBKIT_STRING_PAD_BUG = /Version\/10(?:\.\d+){1,2}(?: [\w./]+)?(?: Mobile\/\w+)? Safari\//.test(USERAGENT);

var DESCRIPTORS_SUPPORT = function () {
return Object.defineProperty({}, 'a', { get: function () { return 7; } }).a == 7;
return Object.defineProperty({}, 'a', {
get: function () { return 7; }
}).a == 7;
};

var V8_PROTOTYPE_DEFINE_BUG = function () {
return Object.defineProperty(function () { /* empty */ }, 'prototype', {
value: 42,
writable: false
}).prototype == 42;
};

var PROMISES_SUPPORT = function () {
Expand Down Expand Up @@ -710,10 +719,10 @@ GLOBAL.tests = {
return Object.create;
},
'es.object.define-getter': OBJECT_PROTOTYPE_ACCESSORS_SUPPORT,
'es.object.define-properties': [DESCRIPTORS_SUPPORT, function () {
'es.object.define-properties': [DESCRIPTORS_SUPPORT, V8_PROTOTYPE_DEFINE_BUG, function () {
return Object.defineProperties;
}],
'es.object.define-property': DESCRIPTORS_SUPPORT,
'es.object.define-property': [DESCRIPTORS_SUPPORT, V8_PROTOTYPE_DEFINE_BUG],
'es.object.define-setter': OBJECT_PROTOTYPE_ACCESSORS_SUPPORT,
'es.object.entries': function () {
return Object.entries;
Expand Down
8 changes: 8 additions & 0 deletions tests/pure/es.object.define-properties.js
Expand Up @@ -10,6 +10,14 @@ QUnit.test('Object.defineProperties', assert => {
assert.same(result, source);
assert.same(result.q, 42);
assert.same(result.w, 33);

if (DESCRIPTORS) {
// eslint-disable-next-line prefer-arrow-callback -- required for testing
assert.same(defineProperties(function () { /* empty */ }, { prototype: {
value: 42,
writable: false,
} }).prototype, 42, 'function prototype with non-writable descriptor');
}
});

QUnit.test('Object.defineProperties.sham flag', assert => {
Expand Down
9 changes: 9 additions & 0 deletions tests/pure/es.object.define-property.js
Expand Up @@ -12,6 +12,15 @@ QUnit.test('Object.defineProperty', assert => {
});
assert.same(result, source);
assert.same(result.q, 42);

if (DESCRIPTORS) {
// eslint-disable-next-line prefer-arrow-callback -- required for testing
assert.same(defineProperty(function () { /* empty */ }, 'prototype', {
value: 42,
writable: false,
}).prototype, 42, 'function prototype with non-writable descriptor');
}

assert.throws(() => defineProperty(42, 1, {}));
assert.throws(() => defineProperty({}, create(null), {}));
assert.throws(() => defineProperty({}, 1, 1));
Expand Down
8 changes: 8 additions & 0 deletions tests/tests/es.object.define-properties.js
Expand Up @@ -12,6 +12,14 @@ QUnit.test('Object.defineProperties', assert => {
assert.same(result, source);
assert.same(result.q, 42);
assert.same(result.w, 33);

if (DESCRIPTORS) {
// eslint-disable-next-line prefer-arrow-callback -- required for testing
assert.same(defineProperties(function () { /* empty */ }, { prototype: {
value: 42,
writable: false,
} }).prototype, 42, 'function prototype with non-writable descriptor');
}
});

QUnit.test('Object.defineProperties.sham flag', assert => {
Expand Down
9 changes: 9 additions & 0 deletions tests/tests/es.object.define-property.js
Expand Up @@ -13,6 +13,15 @@ QUnit.test('Object.defineProperty', assert => {
});
assert.same(result, source);
assert.same(result.q, 42);

if (DESCRIPTORS) {
// eslint-disable-next-line prefer-arrow-callback -- required for testing
assert.same(defineProperty(function () { /* empty */ }, 'prototype', {
value: 42,
writable: false,
}).prototype, 42, 'function prototype with non-writable descriptor');
}

assert.throws(() => defineProperty(42, 1, {}));
assert.throws(() => defineProperty({}, create(null), {}));
assert.throws(() => defineProperty({}, 1, 1));
Expand Down

0 comments on commit 901d97b

Please sign in to comment.