From 1dd8ba779bdc7043a28133876004d7704274d27b Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Sat, 29 May 2021 06:27:21 +0200 Subject: [PATCH] Actually set the prototype when using a __proto__ property (#4112) --- src/ast/nodes/ObjectExpression.ts | 15 +++++++------ test/form/samples/proto-null/_config.js | 3 +++ test/form/samples/proto-null/_expected.js | 2 ++ test/form/samples/proto-null/main.js | 5 +++++ .../samples/proto-accessors/_config.js | 3 +++ test/function/samples/proto-accessors/main.js | 21 +++++++++++++++++++ 6 files changed, 41 insertions(+), 8 deletions(-) create mode 100644 test/form/samples/proto-null/_config.js create mode 100644 test/form/samples/proto-null/_expected.js create mode 100644 test/form/samples/proto-null/main.js create mode 100644 test/function/samples/proto-accessors/_config.js create mode 100644 test/function/samples/proto-accessors/main.js diff --git a/src/ast/nodes/ObjectExpression.ts b/src/ast/nodes/ObjectExpression.ts index 5353905ae41..ca689020cf3 100644 --- a/src/ast/nodes/ObjectExpression.ts +++ b/src/ast/nodes/ObjectExpression.ts @@ -17,12 +17,7 @@ import Literal from './Literal'; import * as NodeType from './NodeType'; import Property from './Property'; import SpreadElement from './SpreadElement'; -import { - ExpressionEntity, - LiteralValueOrUnknown, - UNKNOWN_EXPRESSION, - UnknownValue -} from './shared/Expression'; +import { ExpressionEntity, LiteralValueOrUnknown, UnknownValue } from './shared/Expression'; import { NodeBase } from './shared/Node'; import { ObjectEntity, ObjectProperty } from './shared/ObjectEntity'; import { OBJECT_PROTOTYPE } from './shared/ObjectPrototype'; @@ -112,6 +107,7 @@ export default class ObjectExpression extends NodeBase implements DeoptimizableE if (this.objectEntity !== null) { return this.objectEntity; } + let prototype: ExpressionEntity | null = OBJECT_PROTOTYPE; const properties: ObjectProperty[] = []; for (const property of this.properties) { if (property instanceof SpreadElement) { @@ -137,12 +133,15 @@ export default class ObjectExpression extends NodeBase implements DeoptimizableE ? property.key.name : String((property.key as Literal).value); if (key === '__proto__' && property.kind === 'init') { - properties.unshift({ key: UnknownKey, kind: 'init', property: UNKNOWN_EXPRESSION }); + prototype = + property.value instanceof Literal && property.value.value === null + ? null + : property.value; continue; } } properties.push({ key, kind: property.kind, property }); } - return (this.objectEntity = new ObjectEntity(properties, OBJECT_PROTOTYPE)); + return (this.objectEntity = new ObjectEntity(properties, prototype)); } } diff --git a/test/form/samples/proto-null/_config.js b/test/form/samples/proto-null/_config.js new file mode 100644 index 00000000000..cdbdcecf206 --- /dev/null +++ b/test/form/samples/proto-null/_config.js @@ -0,0 +1,3 @@ +module.exports = { + description: 'handles getters and setters on __proto__ properties' +}; diff --git a/test/form/samples/proto-null/_expected.js b/test/form/samples/proto-null/_expected.js new file mode 100644 index 00000000000..9f5b3e679a4 --- /dev/null +++ b/test/form/samples/proto-null/_expected.js @@ -0,0 +1,2 @@ +console.log('retained'); +console.log('retained'); diff --git a/test/form/samples/proto-null/main.js b/test/form/samples/proto-null/main.js new file mode 100644 index 00000000000..0fed2bf752b --- /dev/null +++ b/test/form/samples/proto-null/main.js @@ -0,0 +1,5 @@ +const a = { __proto__: null }; +if (a.hasOwnProperty) console.log('removed'); +else console.log('retained'); +if (a.foo) console.log('removed'); +else console.log('retained'); diff --git a/test/function/samples/proto-accessors/_config.js b/test/function/samples/proto-accessors/_config.js new file mode 100644 index 00000000000..cdbdcecf206 --- /dev/null +++ b/test/function/samples/proto-accessors/_config.js @@ -0,0 +1,3 @@ +module.exports = { + description: 'handles getters and setters on __proto__ properties' +}; diff --git a/test/function/samples/proto-accessors/main.js b/test/function/samples/proto-accessors/main.js new file mode 100644 index 00000000000..4c9e0129743 --- /dev/null +++ b/test/function/samples/proto-accessors/main.js @@ -0,0 +1,21 @@ +let getter_effect = 'FAIL'; +let setter_effect = 'FAIL'; +let proto = { + get foo() { + getter_effect = 'PASS'; + }, + set bar(value) { + setter_effect = 'PASS'; + } +}; +let obj1 = { + __proto__: proto +}; +let obj2 = { + __proto__: proto +}; +let unused = obj1.foo; +obj2.bar = 0; + +assert.strictEqual(getter_effect, 'PASS'); +assert.strictEqual(setter_effect, 'PASS');