shim: evaluate() should yield a useful stack trace
MODIFY
shim/src/realmFacade.js
shim/src/realmFacade.js
@@ -33,7 +33,7 @@ function buildChildRealm(BaseRealm) {
// err is a primitive value, which is safe to rethrow
throw err;
}
- let eName, eMessage;
+ let eName, eMessage, eStack;
try {
// The child environment might seek to use 'err' to reach the
// parent's intrinsics and corrupt them. `${err.name}` will cause
@@ -47,16 +47,21 @@ function buildChildRealm(BaseRealm) {
// they aren't useful for an attack.
eName = `${err.name}`;
eMessage = `${err.message}`;
- // eName and eMessage are now child-realm primitive strings, and safe
- // to expose
+ eStack = `${err.stack}`;
+ // eName/eMessage/eStack are now child-realm primitive strings, and
+ // safe to expose
} catch (ignored) {
// if err.name.toString() throws, keep the (parent realm) Error away
// from the child
throw new Error('unknown error');
}
const ErrorConstructor = errorConstructors.get(eName) || Error;
- // note: this drops the stack trace. todo: stringify and copy
+ try {
throw new ErrorConstructor(eMessage);
+ } catch (err2) {
+ err2.stack = eStack; // replace with the captured inner stack
+ throw err2;
+ }
}
}

MODIFY
shim/test/realm/leak-error.js
shim/test/realm/leak-error.js
@@ -81,3 +81,22 @@ test('eval() with non-parsable string should not leak SyntaxError', t => {
t.ok(e instanceof r.global.SyntaxError);
t.end();
});
+
+test('eval() should yield useful stack trace', t => {
+ const r = Realm.makeRootRealm();
+ // t.throws() doesn't provide a way to look a e.stack
+ function outer8155() {
+ r.evaluate('function inner9184() { throw TypeError("yes1773"); } inner9184()');
+ }
+ try {
+ outer8155();
+ t.fail('should have thrown');
+ } catch (e) {
+ t.assert(e instanceof TypeError);
+ const stack = e.stack;
+ // stack should contain both inner and outer stacks
+ t.notEqual(stack.indexOf('outer8155'), -1); // outer
+ t.notEqual(stack.indexOf('inner9184'), -1); // inner
+ }
+ t.end();
+});

shim: evaluate() should yield a useful stack trace