Skip to content

Commit

Permalink
fix: tame Error constructor
Browse files Browse the repository at this point in the history
  • Loading branch information
erights committed Jun 27, 2020
1 parent 198c780 commit 0aa101d
Showing 1 changed file with 87 additions and 0 deletions.
87 changes: 87 additions & 0 deletions packages/ses/src/tame-global-error-object.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,42 @@ export const NativeErrors = [
URIError,
];

// Whitelist names from https://v8.dev/docs/stack-trace-api
// Whitelisting only the names used by error-stack-shim/src/v8StackFrames
// callSiteToFrame to shim the error stack proposal.
const safeV8CallSiteMethodNames = [
// suppress 'getThis' definitely
'getTypeName',
// suppress 'getFunction' definitely
'getFunctionName',
'getMethodName',
'getFileName',
'getLineNumber',
'getColumnNumber',
'getEvalOrigin',
// suppress 'isTopLevel' for now
'isEval',
// suppress 'isNative' for now
'isConstructor',
'isAsync',
// suppress 'isPromiseAll' for now
// suppress 'getPromiseIndex' for now

// Additional names found by experiment, absent from
// https://v8.dev/docs/stack-trace-api

// suppress 'getPosition' for now
// suppress 'getScriptNameOrSourceURL' for now
'toString', // TODO replace to use only whitelisted info
];

const safeV8CallSiteFacet = callSite => {
const methodEntry = name => [name, () => callSite[name]()];
return Object.fromEntries(safeV8CallSiteMethodNames.map(methodEntry));
};

const safeV8SST = sst => sst.map(safeV8CallSiteFacet);

export default function tameGlobalErrorObject(errorTaming = 'safe') {
if (errorTaming !== 'safe' && errorTaming !== 'unsafe') {
throw new Error(`unrecognized errorTaming ${errorTaming}`);
Expand Down Expand Up @@ -38,6 +74,8 @@ export default function tameGlobalErrorObject(errorTaming = 'safe') {
};
*/

let userPrepareStackTrace;

// Use concise methods to obtain named functions without constructors.
const tamedMethods = {
captureStackTrace(error, optFn = undefined) {
Expand All @@ -51,6 +89,12 @@ export default function tameGlobalErrorObject(errorTaming = 'safe') {
}
Reflect.set(error, 'stack', '');
},
prepareStackTrace(error, sst) {
if (typeof userPrepareStackTrace === 'function') {
return userPrepareStackTrace(error, safeV8SST(sst));
}
return [`${error}`, ...sst.map(callSite => `${callSite}`)].join('\n ');
},
};

const ErrorPrototype = originalError.prototype;
Expand Down Expand Up @@ -97,6 +141,39 @@ export default function tameGlobalErrorObject(errorTaming = 'safe') {
enumerable: false,
configurable: true,
},
prepareStackTrace: {
get() {
if (
errorTaming === 'unsafe' &&
typeof userPrepareStackTrace === 'function'
) {
return tamedMethods.prepareStackTrace;
}
// By returning undefined, hopefully this means the VM will next consult
// originalError.prepareStackTrace, even on node despite
// https://bugs.chromium.org/p/v8/issues/detail?id=10551#c3
// or, if absent, fallback to the default behavior.
return undefined;
},
set(newPrepareStackTrace) {
if (errorTaming === 'unsafe') {
if (typeof newPrepareStackTrace === 'function') {
userPrepareStackTrace = newPrepareStackTrace;
originalError.prepareStackTrace = tamedMethods.prepareStackTrace;
} else {
userPrepareStackTrace = undefined;
delete originalError.prepareStackTrace;
}
// We place the useless return on the next line to ensure
// that anything we place after the if in the future only
// happens if the then-case does not.
// eslint-disable-next-line no-useless-return
return;
}
},
enumerable: false,
configurable: true,
},
});

// TODO uncomment. See TODO note above
Expand All @@ -120,6 +197,16 @@ export default function tameGlobalErrorObject(errorTaming = 'safe') {
enumerable: false,
configurable: true,
},
prepareStackTrace: {
get() {
return undefined;
},
set(_) {
// ignore
},
enumerable: false,
configurable: true,
},
});
*/

Expand Down

0 comments on commit 0aa101d

Please sign in to comment.