1105d7ba5f
Notes: https://docs.google.com/document/d/1fEumNPCcOn4X0N5jGlAT7GQ5CEKKnw0YxLPXMoaSK5Q/edit?usp=sharing Bug: v8:11374 Change-Id: I96720c0d69fe28e7229c4c22ed3d291587b73f59 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2667511 Commit-Queue: Marja Hölttä <marja@chromium.org> Reviewed-by: Leszek Swirski <leszeks@chromium.org> Reviewed-by: Igor Sheludko <ishell@chromium.org> Reviewed-by: Shu-yu Guo <syg@chromium.org> Cr-Commit-Position: refs/heads/master@{#72659}
568 lines
11 KiB
JavaScript
568 lines
11 KiB
JavaScript
// Copyright 2021 the V8 project authors. All rights reserved.
|
||
// Use of this source code is governed by a BSD-style license that can be
|
||
// found in the LICENSE file.
|
||
|
||
// Flags: --harmony-private-brand-checks --allow-natives-syntax
|
||
|
||
// Objects for which all our brand checks return false.
|
||
const commonFalseCases = [{}, function() {}, []];
|
||
// Values for which all our brand checks throw.
|
||
const commonThrowCases = [100, 'foo', undefined, null];
|
||
|
||
(function TestReturnValue() {
|
||
class A {
|
||
m() {
|
||
assertEquals(typeof (#x in this), 'boolean');
|
||
assertEquals(typeof (#x in {}), 'boolean');
|
||
}
|
||
#x = 1;
|
||
}
|
||
})();
|
||
|
||
(function TestPrivateField() {
|
||
class A {
|
||
m(other) {
|
||
return #x in other;
|
||
}
|
||
#x = 1;
|
||
}
|
||
let a = new A();
|
||
assertTrue(a.m(a));
|
||
assertTrue(a.m(new A()));
|
||
for (o of commonFalseCases) {
|
||
assertFalse(a.m(o));
|
||
}
|
||
for (o of commonThrowCases) {
|
||
assertThrows(() => { a.m(o) }, TypeError);
|
||
}
|
||
|
||
class B {
|
||
#x = 5;
|
||
}
|
||
assertFalse(a.m(new B()));
|
||
})();
|
||
|
||
(function TestPrivateFieldWithValueUndefined() {
|
||
class A {
|
||
m(other) {
|
||
return #x in other;
|
||
}
|
||
#x;
|
||
}
|
||
let a = new A();
|
||
assertTrue(a.m(a));
|
||
assertTrue(a.m(new A()));
|
||
for (o of commonFalseCases) {
|
||
assertFalse(a.m(o));
|
||
}
|
||
for (o of commonThrowCases) {
|
||
assertThrows(() => { a.m(o) }, TypeError);
|
||
}
|
||
|
||
class B {
|
||
#x;
|
||
}
|
||
assertFalse(a.m(new B()));
|
||
})();
|
||
|
||
(function TestPrivateMethod() {
|
||
class A {
|
||
#pm() {
|
||
}
|
||
m(other) {
|
||
return #pm in other;
|
||
}
|
||
}
|
||
let a = new A();
|
||
assertTrue(a.m(a));
|
||
assertTrue(a.m(new A()));
|
||
for (o of commonFalseCases) {
|
||
assertFalse(a.m(o));
|
||
}
|
||
for (o of commonThrowCases) {
|
||
assertThrows(() => { a.m(o) }, TypeError);
|
||
}
|
||
|
||
class B {
|
||
#pm() {}
|
||
}
|
||
assertFalse(a.m(new B()));
|
||
})();
|
||
|
||
(function TestPrivateGetter() {
|
||
class A {
|
||
get #foo() {
|
||
}
|
||
m(other) {
|
||
return #foo in other;
|
||
}
|
||
}
|
||
let a = new A();
|
||
assertTrue(a.m(a));
|
||
assertTrue(a.m(new A()));
|
||
for (o of commonFalseCases) {
|
||
assertFalse(a.m(o));
|
||
}
|
||
for (o of commonThrowCases) {
|
||
assertThrows(() => { a.m(o) }, TypeError);
|
||
}
|
||
|
||
class B {
|
||
get #foo() {}
|
||
}
|
||
assertFalse(a.m(new B()));
|
||
})();
|
||
|
||
(function TestPrivateSetter() {
|
||
class A {
|
||
set #foo(a) {
|
||
}
|
||
m(other) {
|
||
return #foo in other;
|
||
}
|
||
}
|
||
let a = new A();
|
||
assertTrue(a.m(a));
|
||
assertTrue(a.m(new A()));
|
||
for (o of commonFalseCases) {
|
||
assertFalse(a.m(o));
|
||
}
|
||
for (o of commonThrowCases) {
|
||
assertThrows(() => { a.m(o) }, TypeError);
|
||
}
|
||
|
||
class B {
|
||
set #foo(a) {}
|
||
}
|
||
assertFalse(a.m(new B()));
|
||
})();
|
||
|
||
(function TestPrivateGetterAndSetter() {
|
||
class A {
|
||
get #foo() {}
|
||
set #foo(a) {
|
||
}
|
||
m(other) {
|
||
return #foo in other;
|
||
}
|
||
}
|
||
let a = new A();
|
||
assertTrue(a.m(a));
|
||
assertTrue(a.m(new A()));
|
||
for (o of commonFalseCases) {
|
||
assertFalse(a.m(o));
|
||
}
|
||
for (o of commonThrowCases) {
|
||
assertThrows(() => { a.m(o) }, TypeError);
|
||
}
|
||
|
||
class B {
|
||
get #foo() {}
|
||
set #foo(a) {}
|
||
}
|
||
assertFalse(a.m(new B()));
|
||
})();
|
||
|
||
(function TestPrivateStaticField() {
|
||
class A {
|
||
static m(other) {
|
||
return #x in other;
|
||
}
|
||
static #x = 1;
|
||
}
|
||
assertTrue(A.m(A));
|
||
assertFalse(A.m(new A()));
|
||
for (o of commonFalseCases) {
|
||
assertFalse(A.m(o));
|
||
}
|
||
for (o of commonThrowCases) {
|
||
assertThrows(() => { A.m(o) }, TypeError);
|
||
}
|
||
|
||
class B {
|
||
static #x = 5;
|
||
}
|
||
assertFalse(A.m(B));
|
||
})();
|
||
|
||
(function TestPrivateStaticMethod() {
|
||
class A {
|
||
static m(other) {
|
||
return #pm in other;
|
||
}
|
||
static #pm() {}
|
||
}
|
||
assertTrue(A.m(A));
|
||
assertFalse(A.m(new A()));
|
||
for (o of commonFalseCases) {
|
||
assertFalse(A.m(o));
|
||
}
|
||
for (o of commonThrowCases) {
|
||
assertThrows(() => { A.m(o) }, TypeError);
|
||
}
|
||
|
||
class B {
|
||
static #pm() {};
|
||
}
|
||
assertFalse(A.m(B));
|
||
})();
|
||
|
||
(function TestPrivateStaticGetter() {
|
||
class A {
|
||
static m(other) {
|
||
return #x in other;
|
||
}
|
||
static get #x() {}
|
||
}
|
||
assertTrue(A.m(A));
|
||
assertFalse(A.m(new A()));
|
||
for (o of commonFalseCases) {
|
||
assertFalse(A.m(o));
|
||
}
|
||
for (o of commonThrowCases) {
|
||
assertThrows(() => { A.m(o) }, TypeError);
|
||
}
|
||
|
||
class B {
|
||
static get #x() {};
|
||
}
|
||
assertFalse(A.m(B));
|
||
})();
|
||
|
||
(function TestPrivateStaticSetter() {
|
||
class A {
|
||
static m(other) {
|
||
return #x in other;
|
||
}
|
||
static set #x(x) {}
|
||
}
|
||
assertTrue(A.m(A));
|
||
assertFalse(A.m(new A()));
|
||
for (o of commonFalseCases) {
|
||
assertFalse(A.m(o));
|
||
}
|
||
for (o of commonThrowCases) {
|
||
assertThrows(() => { A.m(o) }, TypeError);
|
||
}
|
||
|
||
class B {
|
||
static set #x(x) {};
|
||
}
|
||
assertFalse(A.m(B));
|
||
})();
|
||
|
||
(function TestPrivateStaticGetterAndSetter() {
|
||
class A {
|
||
static m(other) {
|
||
return #x in other;
|
||
}
|
||
static get #x() {}
|
||
static set #x(x) {}
|
||
}
|
||
assertTrue(A.m(A));
|
||
assertFalse(A.m(new A()));
|
||
for (o of commonFalseCases) {
|
||
assertFalse(A.m(o));
|
||
}
|
||
for (o of commonThrowCases) {
|
||
assertThrows(() => { A.m(o) }, TypeError);
|
||
}
|
||
|
||
class B {
|
||
static get #x() {}
|
||
static set #x(x) {};
|
||
}
|
||
assertFalse(A.m(B));
|
||
})();
|
||
|
||
(function TestPrivateIdentifiersAreDistinct() {
|
||
function GenerateClass() {
|
||
class A {
|
||
m(other) {
|
||
return #x in other;
|
||
}
|
||
#x = 0;
|
||
}
|
||
return new A();
|
||
}
|
||
let a1 = GenerateClass();
|
||
let a2 = GenerateClass();
|
||
assertTrue(a1.m(a1));
|
||
assertFalse(a1.m(a2));
|
||
assertFalse(a2.m(a1));
|
||
assertTrue(a2.m(a2));
|
||
})();
|
||
|
||
(function TestSubclasses() {
|
||
class A {
|
||
m(other) { return #foo in other; }
|
||
#foo;
|
||
}
|
||
class B extends A {}
|
||
assertTrue((new A()).m(new B()));
|
||
})();
|
||
|
||
(function TestFakeSubclassesWithPrivateField() {
|
||
class A {
|
||
#foo;
|
||
m() { return #foo in this; }
|
||
}
|
||
let a = new A();
|
||
assertTrue(a.m());
|
||
|
||
// Plug an object into the prototype chain; it's not a real instance of the
|
||
// class.
|
||
let fake = {__proto__: a};
|
||
assertFalse(fake.m());
|
||
})();
|
||
|
||
(function TestFakeSubclassesWithPrivateMethod() {
|
||
class A {
|
||
#pm() {}
|
||
m() { return #pm in this; }
|
||
}
|
||
let a = new A();
|
||
assertTrue(a.m());
|
||
|
||
// Plug an object into the prototype chain; it's not a real instance of the
|
||
// class.
|
||
let fake = {__proto__: a};
|
||
assertFalse(fake.m());
|
||
})();
|
||
|
||
(function TestPrivateNameUnknown() {
|
||
assertThrows(() => { eval(`
|
||
class A {
|
||
m(other) { return #lol in other; }
|
||
}
|
||
new A().m();
|
||
`)}, SyntaxError, /must be declared in an enclosing class/);
|
||
})();
|
||
|
||
(function TestEvalWithPrivateField() {
|
||
class A {
|
||
m(other) {
|
||
let result;
|
||
eval('result = #x in other;');
|
||
return result;
|
||
}
|
||
#x = 1;
|
||
}
|
||
let a = new A();
|
||
assertTrue(a.m(a));
|
||
assertTrue(a.m(new A()));
|
||
for (o of commonFalseCases) {
|
||
assertFalse(a.m(o));
|
||
}
|
||
for (o of commonThrowCases) {
|
||
assertThrows(() => { a.m(o) }, TypeError);
|
||
}
|
||
})();
|
||
|
||
(function TestEvalWithPrivateMethod() {
|
||
class A {
|
||
m(other) {
|
||
let result;
|
||
eval('result = #pm in other;');
|
||
return result;
|
||
}
|
||
#pm() {}
|
||
}
|
||
let a = new A();
|
||
assertTrue(a.m(a));
|
||
assertTrue(a.m(new A()));
|
||
for (o of commonFalseCases) {
|
||
assertFalse(a.m(o));
|
||
}
|
||
for (o of commonThrowCases) {
|
||
assertThrows(() => { a.m(o) }, TypeError);
|
||
}
|
||
})();
|
||
|
||
(function TestEvalWithStaticPrivateField() {
|
||
class A {
|
||
static m(other) {
|
||
let result;
|
||
eval('result = #x in other;');
|
||
return result;
|
||
}
|
||
static #x = 1;
|
||
}
|
||
assertTrue(A.m(A));
|
||
assertFalse(A.m(new A()));
|
||
for (o of commonFalseCases) {
|
||
assertFalse(A.m(o));
|
||
}
|
||
for (o of commonThrowCases) {
|
||
assertThrows(() => { A.m(o) }, TypeError);
|
||
}
|
||
})();
|
||
|
||
(function TestEvalWithStaticPrivateMethod() {
|
||
class A {
|
||
static m(other) {
|
||
let result;
|
||
eval('result = #pm in other;');
|
||
return result;
|
||
}
|
||
static #pm() {}
|
||
}
|
||
assertTrue(A.m(A));
|
||
assertFalse(A.m(new A()));
|
||
for (o of commonFalseCases) {
|
||
assertFalse(A.m(o));
|
||
}
|
||
for (o of commonThrowCases) {
|
||
assertThrows(() => { A.m(o) }, TypeError);
|
||
}
|
||
})();
|
||
|
||
(function TestCombiningWithOtherExpressions() {
|
||
class A {
|
||
m() {
|
||
assertFalse(#x in {} in {} in {});
|
||
assertTrue(#x in this in {true: 0});
|
||
assertTrue(#x in {} < 1 + 1);
|
||
assertFalse(#x in this < 1);
|
||
|
||
assertThrows(() => { eval('#x in {} = 4')});
|
||
assertThrows(() => { eval('(#x in {}) = 4')});
|
||
}
|
||
#x;
|
||
}
|
||
new A().m();
|
||
})();
|
||
|
||
(function TestHalfConstructedObjects() {
|
||
let half_constructed;
|
||
class A {
|
||
m() {
|
||
assertTrue(#x in this);
|
||
assertFalse(#y in this);
|
||
}
|
||
#x = 0;
|
||
#y = (() => { half_constructed = this; throw 'lol';})();
|
||
}
|
||
|
||
try {
|
||
new A();
|
||
} catch {
|
||
}
|
||
half_constructed.m();
|
||
})();
|
||
|
||
(function TestPrivateFieldOpt() {
|
||
class A {
|
||
m(other) {
|
||
return #x in other;
|
||
}
|
||
#x = 1;
|
||
}
|
||
let a = new A();
|
||
%PrepareFunctionForOptimization(A.prototype.m);
|
||
assertTrue(a.m(a));
|
||
assertTrue(a.m(new A()));
|
||
%OptimizeFunctionOnNextCall(A.prototype.m);
|
||
assertTrue(a.m(a));
|
||
assertTrue(a.m(new A()));
|
||
|
||
class B {
|
||
#x = 5;
|
||
}
|
||
assertFalse(a.m(new B()));
|
||
})();
|
||
|
||
(function TestPrivateMethodOpt() {
|
||
class A {
|
||
#pm() {
|
||
}
|
||
m(other) {
|
||
return #pm in other;
|
||
}
|
||
}
|
||
let a = new A();
|
||
%PrepareFunctionForOptimization(A.prototype.m);
|
||
assertTrue(a.m(a));
|
||
assertTrue(a.m(new A()));
|
||
%OptimizeFunctionOnNextCall(A.prototype.m);
|
||
assertTrue(a.m(a));
|
||
assertTrue(a.m(new A()));
|
||
|
||
class B {
|
||
#pm() {}
|
||
}
|
||
assertFalse(a.m(new B()));
|
||
})();
|
||
|
||
(function TestPrivateStaticFieldOpt() {
|
||
class A {
|
||
static m(other) {
|
||
return #x in other;
|
||
}
|
||
static #x = 1;
|
||
}
|
||
%PrepareFunctionForOptimization(A.m);
|
||
assertTrue(A.m(A));
|
||
%OptimizeFunctionOnNextCall(A.m);
|
||
assertTrue(A.m(A));
|
||
|
||
class B {
|
||
static #x = 5;
|
||
}
|
||
assertFalse(A.m(B));
|
||
})();
|
||
|
||
(function TestPrivateStaticMethodOpt() {
|
||
class A {
|
||
static m(other) {
|
||
return #pm in other;
|
||
}
|
||
static #pm() {}
|
||
}
|
||
%PrepareFunctionForOptimization(A.m);
|
||
assertTrue(A.m(A));
|
||
%OptimizeFunctionOnNextCall(A.m);
|
||
assertTrue(A.m(A));
|
||
|
||
class B {
|
||
static #pm() {};
|
||
}
|
||
assertFalse(A.m(B));
|
||
})();
|
||
|
||
(function TestPrivateFieldWithProxy() {
|
||
class A {
|
||
m(other) {
|
||
return #x in other;
|
||
}
|
||
#x = 1;
|
||
}
|
||
let a = new A();
|
||
|
||
const p = new Proxy(a, {get: function() { assertUnreachable(); } });
|
||
assertFalse(a.m(p));
|
||
})();
|
||
|
||
(function TestHeritagePosition() {
|
||
class A {
|
||
#x; // A.#x
|
||
static C = class C extends (function () {
|
||
return class D {
|
||
exfil(obj) { return #x in obj; }
|
||
exfilEval(obj) { return eval("#x in obj"); }
|
||
};
|
||
}) { // C body starts
|
||
#x; // C.#x
|
||
} // C body ends
|
||
} // A ends
|
||
let c = new A.C();
|
||
let d = new c();
|
||
// #x inside D binds to A.#x, so only objects of A pass the check.
|
||
assertTrue(d.exfil(new A()));
|
||
assertFalse(d.exfil(c));
|
||
assertFalse(d.exfil(d));
|
||
assertTrue(d.exfilEval(new A()));
|
||
assertFalse(d.exfilEval(c));
|
||
assertFalse(d.exfilEval(d));
|
||
})();
|