v8/test/mjsunit/harmony/shadowrealm-callsite-throw.js
Shu-yu Guo b69c3770b2 [ShadowRealm] Make CallSite#getFunction/getThis throw for ShadowRealm frames
This CL plugs the hole in the outside<-ShadowRealm direction (i.e.
getting a reference to an object inside of the ShadowRealm from outside
the ShadowRealm).

This is a follow-on CL to
https://chromium-review.googlesource.com/c/v8/v8/+/4108810, which
plugged the getFunction hole in the ShadowRealm<-outside direction (i.e.
getting a reference to an object outside of the ShadowRealm from inside
the ShadowRealm).

Bug: v8:1198
Change-Id: Ic06533ba8b1cc6477ef9d55a23cb8b0b6584d4a6
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4115657
Commit-Queue: Shu-yu Guo <syg@chromium.org>
Reviewed-by: Camillo Bruni <cbruni@chromium.org>
Auto-Submit: Shu-yu Guo <syg@chromium.org>
Cr-Commit-Position: refs/heads/main@{#85003}
2022-12-22 19:06:57 +00:00

115 lines
3.0 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.
// Flags: --harmony-shadow-realm
// Test that CallSite#getFunction and CallSite#getThis throw inside ShadowRealms
// and cannot access objects from the outside, as otherwise we could violate the
// callable boundary invariant.
(function testInside() {
const shadowRealm = new ShadowRealm();
// The ShadowRealm won't have assertThrows, so use try-catch and accumulate a
// message string.
const wrapped = shadowRealm.evaluate(`
Error.prepareStackTrace = function(err, frames) {
let a = [];
for (let i = 0; i < frames.length; i++) {
try {
a.push(frames[i].getFunction());
} catch (e) {
a.push("getFunction threw");
}
try {
a.push(frames[i].getThis());
} catch (e) {
a.push("getThis threw");
}
}
return a.join(' ');
};
function inner() {
try {
throw new Error();
} catch (e) {
return e.stack;
}
}
inner;
`);
(function outer() {
// There are 4 frames, youngest to oldest:
//
// inner
// outer
// testInside
// top-level
//
// So getFunction/getThis should throw 4 times since the prepareStackTrace
// hook is executing inside the ShadowRealm.
assertEquals("getFunction threw getThis threw " +
"getFunction threw getThis threw " +
"getFunction threw getThis threw " +
"getFunction threw getThis threw", wrapped());
})();
})();
// Test that CallSite#getFunction and CallSite#getThis throw for ShadowRealm
// objects from the outside, as otherwise we can also violate the callable
// boundary.
(function testOutside() {
Error.prepareStackTrace = function(err, frames) {
let a = [];
for (let i = 0; i < frames.length; i++) {
try {
frames[i].getFunction();
a.push(`functionName: ${frames[i].getFunctionName()}`);
} catch (e) {
a.push(`${frames[i].getFunctionName()} threw`);
}
try {
frames[i].getThis();
a.push("t");
} catch (e) {
a.push("getThis threw");
}
}
return JSON.stringify(a);
};
const shadowRealm = new ShadowRealm();
const wrap = shadowRealm.evaluate(`
function trampolineMaker(callback) {
return function trampoline() { return callback(); };
}
trampolineMaker;
`);
const wrapped = wrap(function callback() {
try {
throw new Error();
} catch (e) {
return e.stack;
}
});
// There are 4 frames, youngest to oldest:
//
// callback (in outer realm)
// trampoline (in ShadowRealm)
// testOutside (in outer realm)
// top-level (in outer realm)
//
// The frame corresponding to trampoline should throw, since the outer realm
// should not get references to ShadowRealm objects.
assertEquals(JSON.stringify(
["functionName: callback", "t",
"trampoline threw", "getThis threw",
"functionName: testOutside", "t",
"functionName: null", "t"]), wrapped());
assertEquals
})();