You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This document describes the various mechanism that different browsers must implement when exposing message and stack information via Error objects. The objective is to provide guidance for implementers.
3
+
This document describes the various mechanism that different browsers must implement when exposing information via Error objects. The objective is to provide guidance for implementers.
4
4
5
5
## Errors Crossing Callable Boundary
6
6
7
-
Errors thrown across the ShadowRealm's callable boundary in either direction are replaced by a fresh `TypeError` as described by the spec. Additionally, the new `TypeError` instance can be augmented with a `message`and `stack`properties to help developers.
7
+
Errors thrown across the ShadowRealm's callable boundary in either direction are replaced by a fresh `TypeError` as described by the spec. Additionally, the new `TypeError` instance can be augmented with a `message` properties to help developers.
8
8
9
9
### New Error.message
10
10
@@ -22,13 +22,11 @@ New `error.message` after crossing a boundary:
22
22
TypeError: wrapped function threw, error was TypeError: null has no properties
23
23
```
24
24
25
-
This error allows developers to clearly understand that the error was thrown from another Realm. If the error crosses multiple nested ShadowRealms, the second time the error is created when crossing another boundary, the message should still be formed from scratch rather than providing nesting of the message. The same applies to re-entrancing as well since the error re-entring the ShadowRealm where it was originated, will come as a brand new TypeError object, with no connection to the original Error object.
25
+
This error allows developers to clearly understand that the error was thrown from another Realm. If the error crosses multiple nested ShadowRealms, the second time the error is copied when crossing another boundary, the message should still be formed from scratch rather than providing nesting of the message. The same applies to re-entrancing as well since the error re-entering the ShadowRealm where it was originated, will come as a brand new TypeError object, with no visible reference to the original Error object.
26
26
27
-
Accessing the `name` and `message` of the original Error object must not be observed by the user-land code. The following logic may be used:
27
+
Accessing the `name` and `message` of the original Error object must not be observed by user-land code. The following logic may be used:
28
28
29
-
If _originalError_ has an `[[ErrorData]]` internal slot, then use the data values of `name` and `message` of the data properties. In case of accesor properties, use the cached values stored during the creation of the original error by the host.
30
-
31
-
_Note: It is possible to only cache the `name` and `message` if the error could cross a boundary (based on the stack frames)._
29
+
If _originalError_ has an `[[ErrorData]]` internal slot, then use the data values of `name` and `message` of the data properties. In case of accessor properties, use the cached values stored during the creation of the original error by the host.
32
30
33
31
If _originalError_ does not have an `[[ErrorData]]` internal slot, then produce a generic message. E.g.:
34
32
@@ -45,112 +43,3 @@ wrapped function threw, error was uncaught exception: Object
45
43
```
46
44
47
45
_Note: FF implementation follows the logic described above._
48
-
49
-
### error.stack
50
-
51
-
A good error message is sometimes not enough. We encourage engines to enable their engine-specific stack introspection mechanisms for errors in ShadowRealms. In this case, the Error's stack is subject to censorship constraints.
52
-
53
-
Some of the use-cases for ShadowRealm, e.g., the virtualization, require a mechanism to control the error's stack, so those accessing it should not observe that the program is running inside a ShadowRealm. Early versions of the spec were simply nulling out the stack when an error crosses the callable boundary, but that was not sufficient, in fact, it was faulty for two main reasons:
54
-
55
-
1. It was impossible for developers to figure out where the error occurred, including errors from the module graph linkage phase.
56
-
2. Errors originated from within a ShadowRealm, and observed inside the same ShadowRealm, were still leaking all the information.
57
-
58
-
This document describes how to solve both of these problems by applying a censoring process for all errors.
59
-
60
-
#### Censoring Error objects accessible within ShadowRealms
61
-
62
-
The first step is to make sure that when an error of any kind is observed (by reference) inside a ShadowRealm instance, the host is censoring all stack frames that are not associated to the ShadowRealm instance itself. This allows the following example to work properly:
63
-
64
-
```js
65
-
try { null.foo } catch (e) {
66
-
console.log(e.stack);
67
-
throw e;
68
-
}
69
-
```
70
-
71
-
In the example above, `e` never crossed a callable boundary, but regardless, it should not contain a stack frame associated to another realm. Assuming that this error is observed (accessed) in two different places, a try/catch from above when running inside the ShadowRealm instances, and another try/catch in the incubator realm, which happens to be the main page (top level window), we should see two different error's stack for the two different errors:
72
-
73
-
1. ShadowRealm's `error.stack`:
74
-
```
75
-
foo@http://127.0.0.1:8081/y.js:2:5
76
-
bar@http://127.0.0.1:8081/y.js:6:12
77
-
captureStack@http://127.0.0.1:8081/x.js:9:9
78
-
```
79
-
80
-
_Note: Only the 3 stack frames must be exposed on this error because they correspond to code evaluated inside the ShadowRealm associated to the error instance._
81
-
82
-
2. Main page's `Error.stack`:
83
-
```
84
-
foo@http://127.0.0.1:8081/y.js:2:5
85
-
bar@http://127.0.0.1:8081/y.js:6:12
86
-
captureStack@http://127.0.0.1:8081/x.js:9:9
87
-
runInSandbox@http://127.0.0.1:8081/demo.html:6:17
88
-
@http://127.0.0.1:8081/demo.html:8:1
89
-
```
90
-
91
-
_Note: All 5 stack frames should be exposed on this error regardless of their location and associated Realms, this is analogous to what happen with same domain iframes today._
92
-
93
-
In the example above, we have 2 modules, `x.js` and `y.js`:
94
-
95
-
```js
96
-
import { foo, bar } from'./y.js';
97
-
98
-
exportfunctionletItThrow() {
99
-
returnfoo();
100
-
}
101
-
102
-
exportfunctioncaptureStack() {
103
-
try {
104
-
bar();
105
-
} catch (e) {
106
-
returne.stack;
107
-
}
108
-
return'';
109
-
}
110
-
```
111
-
112
-
```js
113
-
exportfunctionfoo() {
114
-
returnnull.x;
115
-
}
116
-
117
-
exportfunctionbar() {
118
-
returnfoo();
119
-
}
120
-
```
121
-
122
-
The incubator realm running (demo.html) can do the following:
Since ShadowRealm provides integrity guarantees, errors instances belonging to a ShadowRealm are only accessible inside the ShadowRealm (thanks to the callable boundary), this censoring process only affect errors inside a ShadowRealm, developers, and dev-tools observing errors at the top level (main window), should still be able to observe the full stack information. This covers tools to collect metrics about errors, and any other mechanism running on the main program.
138
-
139
-
### Example
140
-
141
-
Now, let's assume that we have 3 programs:
142
-
143
-
- Main Program (running on top level)
144
-
- Program A (running inside a ShadowRealm created by the Main Program)
145
-
- Program B (running inside a ShadowRealm created by Program A)
146
-
147
-
The same mechanism must be applied if the error was generated by a child ShadowRealm B (Program B), which was created by Program A. Let's explore the different scenarios:
148
-
149
-
1. A try/catch in Program B catches the error, it will qualify to be censored, only revealing stack frames associated to the ShadowRealm where Program B runs, and none from Program A or the Main Program.
150
-
1. A try/catch in Program A catches the error, it will qualify to be censored, only revealing stack frames associated to the ShadowRealm where Program A runs, and none from Program B or the Main Program.
151
-
152
-
Hosts can:
153
-
154
-
a) identify, at the time of creation of the original Error instance, if that error might cross the callable boundary, and store the original stack information, along with the `name` and `meessage`.
155
-
b) generate a censored stack information depending on the realm observing the error.
156
-
c) generate the stack information lazily by producing the stack when it is accessed the first time per realm.
0 commit comments