v8/test/mjsunit/regress/regress-crbug-1321899.js
Joyee Cheung 81c14eb85d [runtime] return when failed access callback doesn't throw
When the failed access callback is configured but it doesn't throw,
we should return instead of expecting an exception, otherwise
it would crash because there isn't one.

This patch also adds --throw-on-failed-access-check and
--noop-on-failed-access-check in d8 to mimic the behavior
of the failed access check callback in chromium.

Bug: chromium:1339722
Change-Id: Ie1db9d2fb364c6f8259eb9b8d81a21071c280a80
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3737305
Commit-Queue: Joyee Cheung <joyee@igalia.com>
Reviewed-by: Toon Verwaest <verwaest@chromium.org>
Cr-Commit-Position: refs/heads/main@{#81557}
2022-07-06 14:01:36 +00:00

173 lines
6.1 KiB
JavaScript

// Copyright 2022 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.
class A {
constructor(arg) {
return arg;
}
}
class B extends A {
#b = 1; // ACCESS_CHECK -> DATA
constructor(arg) {
super(arg);
}
static setField(obj) {
obj.#b = 'b'; // KeyedStoreIC
}
static getField(obj) {
return obj.#b;
}
static hasField(obj) {
return #b in obj;
}
}
class C extends A {
#c; // DefineKeyedOwnIC: ACCESS_CHECK -> NOT_FOUND
constructor(arg) {
super(arg);
}
static setField(obj) {
obj.#c = 'c'; // KeyedStoreIC
}
static getField(obj) {
return obj.#c;
}
static hasField(obj) {
return #c in obj;
}
}
let d = 0;
class D extends A {
get #d() { return d; }
set #d(val) { d = val; }
constructor(arg) {
super(arg); // KeyedStoreIC for private brand
}
static setAccessor(obj) {
obj.#d = 'd'; // KeyedLoadIC for private brand
}
static getAccessor(obj) {
return obj.#d; // KeyedLoadIC for private brand
}
static hasAccessor(obj) {
return #d in obj;
}
}
class E extends A {
#e() { return 0; }
constructor(arg) {
super(arg); // KeyedStoreIC for private brand
}
static setMethod(obj) {
obj.#e = 'e'; // KeyedLoadIC for private brand
}
static getMethod(obj) {
return obj.#e; // KeyedLoadIC for private brand
}
static hasMethod(obj) {
return #e in obj;
}
}
function checkHasAccess(object) {
assertThrows(() => B.setField(globalProxy), TypeError, /Cannot write private member #b to an object whose class did not declare it/);
assertThrows(() => B.getField(globalProxy), TypeError, /Cannot read private member #b from an object whose class did not declare it/);
assertFalse(B.hasField(globalProxy));
new B(globalProxy);
assertEquals(B.getField(globalProxy), 1);
B.setField(globalProxy);
assertEquals(B.getField(globalProxy), 'b'); // Fast case
B.setField(globalProxy); // Fast case
assertEquals(B.getField(globalProxy), 'b'); // Fast case
assertThrows(() => new B(globalProxy), TypeError, /Cannot initialize #b twice on the same object/);
assertTrue(B.hasField(globalProxy));
assertTrue(B.hasField(globalProxy)); // Fast case
assertThrows(() => C.setField(globalProxy), TypeError, /Cannot write private member #c to an object whose class did not declare it/);
assertThrows(() => C.getField(globalProxy), TypeError, /Cannot read private member #c from an object whose class did not declare it/);
assertFalse(C.hasField(globalProxy));
new C(globalProxy);
assertEquals(C.getField(globalProxy), undefined);
C.setField(globalProxy);
assertEquals(C.getField(globalProxy), 'c'); // Fast case
C.setField(globalProxy); // Fast case
assertEquals(C.getField(globalProxy), 'c'); // Fast case
assertThrows(() => new C(globalProxy), TypeError, /Cannot initialize #c twice on the same object/);
assertTrue(C.hasField(globalProxy));
assertTrue(C.hasField(globalProxy)); // Fast case
assertThrows(() => D.setAccessor(globalProxy), TypeError, /Receiver must be an instance of class D/);
assertThrows(() => D.getAccessor(globalProxy), TypeError, /Receiver must be an instance of class D/);
assertFalse(D.hasAccessor(globalProxy));
new D(globalProxy);
assertEquals(D.getAccessor(globalProxy), 0);
D.setAccessor(globalProxy);
assertEquals(D.getAccessor(globalProxy), 'd'); // Fast case
D.setAccessor(globalProxy); // Fast case
assertEquals(D.getAccessor(globalProxy), 'd'); // Fast case
assertThrows(() => new D(globalProxy), TypeError, /Cannot initialize private methods of class D twice on the same object/);
assertTrue(D.hasAccessor(globalProxy));
assertTrue(D.hasAccessor(globalProxy)); // Fast case
assertThrows(() => E.setMethod(globalProxy), TypeError, /Receiver must be an instance of class E/);
assertThrows(() => E.getMethod(globalProxy), TypeError, /Receiver must be an instance of class E/);
assertFalse(E.hasMethod(globalProxy));
new E(globalProxy);
assertEquals(E.getMethod(globalProxy)(), 0);
assertThrows(() => E.setMethod(globalProxy), TypeError, /Private method '#e' is not writable/);
assertEquals(E.getMethod(globalProxy)(), 0); // Fast case
assertThrows(() => new E(globalProxy), TypeError, /Cannot initialize private methods of class E twice on the same object/);
assertTrue(E.hasMethod(globalProxy));
assertTrue(E.hasMethod(globalProxy)); // Fast case
}
function checkNoAccess(object, message) {
assertThrows(() => new B(object), Error, message);
assertThrows(() => new C(object), Error, message);
assertThrows(() => new D(object), Error, message);
assertThrows(() => new E(object), Error, message);
assertThrows(() => B.setField(object), Error, message);
assertThrows(() => B.getField(object), Error, message);
assertThrows(() => B.hasField(object), Error, message);
assertThrows(() => C.setField(object), Error, message);
assertThrows(() => C.getField(object), Error, message);
assertThrows(() => C.hasField(object), Error, message);
assertThrows(() => D.setAccessor(object), Error, message);
assertThrows(() => D.getAccessor(object), Error, message);
assertThrows(() => D.hasAccessor(object), Error, message);
assertThrows(() => E.setMethod(object), Error, message);
assertThrows(() => E.getMethod(object), Error, message);
assertThrows(() => E.hasMethod(object), Error, message);
}
function checkNoAccessNoThrow(object) {
// The failed access check callback is supposed to throw.
// If it doesn't the behavior is quite quirky.
// This only documents the current behavior.
new B(object);
new C(object);
new D(object);
new E(object);
B.setField(object);
assertEquals(undefined, B.getField(object));
assertFalse(B.hasField(object));
C.setField(object);
assertEquals(undefined, C.getField(object));
assertFalse(C.hasField(object));
D.setAccessor(object)
assertEquals("d", D.getAccessor(object));
assertFalse(D.hasAccessor(object));
assertThrows(() => E.setMethod(object), TypeError, /Private method '#e' is not writable/);
assertEquals(0, E.getMethod(object)());
assertFalse(E.hasMethod(object));
}