From 70c77e550c0c1be3ed01fd07699e7cc4dee98b10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hu=C3=A1ng=20J=C3=B9nli=C3=A0ng?= Date: Wed, 3 Mar 2021 15:06:38 -0500 Subject: [PATCH] check descriptor before private field access (#12910) * fix: check descriptor before private field access * add test cases --- packages/babel-helpers/src/helpers.js | 9 ++++++ .../access-before-declaration/exec.js | 29 +++++++++++++++++++ .../private/access-before-declaration/exec.js | 29 +++++++++++++++++++ .../access-before-declaration/exec.js | 29 +++++++++++++++++++ .../access-before-declaration/exec.js | 29 +++++++++++++++++++ .../access-before-declaration/exec.js | 29 +++++++++++++++++++ 6 files changed, 154 insertions(+) create mode 100644 packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/access-before-declaration/exec.js create mode 100644 packages/babel-plugin-proposal-class-properties/test/fixtures/private/access-before-declaration/exec.js create mode 100644 packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/access-before-declaration/exec.js create mode 100644 packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-privateFieldsAsProperties/access-before-declaration/exec.js create mode 100644 packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/access-before-declaration/exec.js diff --git a/packages/babel-helpers/src/helpers.js b/packages/babel-helpers/src/helpers.js index f0d1a88592f7..0de3ea2d1efa 100644 --- a/packages/babel-helpers/src/helpers.js +++ b/packages/babel-helpers/src/helpers.js @@ -1336,6 +1336,9 @@ helpers.classPrivateFieldSet = helper("7.0.0-beta.0")` helpers.classPrivateFieldDestructureSet = helper("7.4.4")` export default function _classPrivateFieldDestructureSet(receiver, privateMap) { + if (privateMap === undefined) { + throw new TypeError("attempted to set private static field before its declaration"); + } if (!privateMap.has(receiver)) { throw new TypeError("attempted to set private field on non-instance"); } @@ -1367,6 +1370,9 @@ helpers.classStaticPrivateFieldSpecGet = helper("7.0.2")` if (receiver !== classConstructor) { throw new TypeError("Private static access of wrong provenance"); } + if (descriptor === undefined) { + throw new TypeError("attempted to get private static field before its declaration"); + } if (descriptor.get) { return descriptor.get.call(receiver); } @@ -1379,6 +1385,9 @@ helpers.classStaticPrivateFieldSpecSet = helper("7.0.2")` if (receiver !== classConstructor) { throw new TypeError("Private static access of wrong provenance"); } + if (descriptor === undefined) { + throw new TypeError("attempted to set private static field before its declaration"); + } if (descriptor.set) { descriptor.set.call(receiver, value); } else { diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/access-before-declaration/exec.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/access-before-declaration/exec.js new file mode 100644 index 000000000000..dc329788a1fa --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/access-before-declaration/exec.js @@ -0,0 +1,29 @@ +expect(() => { + class C { + static #_ = new C; + static #p; + constructor() { + C.#p; + } + } +}).toThrow(/attempted to use private field on non-instance/); + +expect(() => { + class C { + static #_ = new C; + static #p; + constructor() { + C.#p = 0; + } + } +}).toThrow(/attempted to use private field on non-instance/); + +expect(() => { + class C { + static #_ = new C; + static #p; + constructor() { + for (C.#p of [0]); + } + } +}).toThrow(/attempted to use private field on non-instance/); diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/access-before-declaration/exec.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/access-before-declaration/exec.js new file mode 100644 index 000000000000..e5c4a2f5a119 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/access-before-declaration/exec.js @@ -0,0 +1,29 @@ +expect(() => { + class C { + static #_ = new C; + static #p; + constructor() { + C.#p; + } + } +}).toThrow(/attempted to get private static field before its declaration/); + +expect(() => { + class C { + static #_ = new C; + static #p; + constructor() { + C.#p = 0; + } + } +}).toThrow(/attempted to set private static field before its declaration/); + +expect(() => { + class C { + static #_ = new C; + static #p; + constructor() { + for (C.#p of [0]); + } + } +}).toThrow(/attempted to set private static field before its declaration/); diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/access-before-declaration/exec.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/access-before-declaration/exec.js new file mode 100644 index 000000000000..792eaa32fe41 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/access-before-declaration/exec.js @@ -0,0 +1,29 @@ +expect(() => { + class C { + static #_ = new C; + static get #p() { return C }; + constructor() { + C.#p; + } + } +}).toThrow(/attempted to use private field on non-instance/); + +expect(() => { + class C { + static #_ = new C; + static set #p(v) {}; + constructor() { + C.#p = 0; + } + } +}).toThrow(/attempted to use private field on non-instance/); + +expect(() => { + class C { + static #_ = new C; + static set #p(v) {}; + constructor() { + for (C.#p of [0]); + } + } +}).toThrow(/attempted to use private field on non-instance/); diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-privateFieldsAsProperties/access-before-declaration/exec.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-privateFieldsAsProperties/access-before-declaration/exec.js new file mode 100644 index 000000000000..792eaa32fe41 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-privateFieldsAsProperties/access-before-declaration/exec.js @@ -0,0 +1,29 @@ +expect(() => { + class C { + static #_ = new C; + static get #p() { return C }; + constructor() { + C.#p; + } + } +}).toThrow(/attempted to use private field on non-instance/); + +expect(() => { + class C { + static #_ = new C; + static set #p(v) {}; + constructor() { + C.#p = 0; + } + } +}).toThrow(/attempted to use private field on non-instance/); + +expect(() => { + class C { + static #_ = new C; + static set #p(v) {}; + constructor() { + for (C.#p of [0]); + } + } +}).toThrow(/attempted to use private field on non-instance/); diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/access-before-declaration/exec.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/access-before-declaration/exec.js new file mode 100644 index 000000000000..6555875117e7 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/access-before-declaration/exec.js @@ -0,0 +1,29 @@ +expect(() => { + class C { + static #_ = new C; + static get #p() { return C }; + constructor() { + C.#p; + } + } +}).toThrow(/attempted to get private static field before its declaration/); + +expect(() => { + class C { + static #_ = new C; + static set #p(v) {}; + constructor() { + C.#p = 0; + } + } +}).toThrow(/attempted to set private static field before its declaration/); + +expect(() => { + class C { + static #_ = new C; + static set #p(v) {}; + constructor() { + for (C.#p of [0]); + } + } +}).toThrow(/attempted to set private static field before its declaration/);