1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
|
// 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
})();
|