promises: more robust stringification
PR-URL: https://github.com/nodejs/node/pull/13784 Fixes: https://github.com/nodejs/node/issues/13771 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Rod Vagg <rod@vagg.org> Reviewed-By: Michaël Zasso <targos@protonmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
parent
11b7428832
commit
428bcb7877
@ -1,5 +1,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
const { safeToString } = process.binding('util');
|
||||||
|
|
||||||
const promiseRejectEvent = process._promiseRejectEvent;
|
const promiseRejectEvent = process._promiseRejectEvent;
|
||||||
const hasBeenNotifiedProperty = new WeakMap();
|
const hasBeenNotifiedProperty = new WeakMap();
|
||||||
const promiseToGuidProperty = new WeakMap();
|
const promiseToGuidProperty = new WeakMap();
|
||||||
@ -58,12 +60,17 @@ function setupPromises(scheduleMicrotasks) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function emitWarning(uid, reason) {
|
function emitWarning(uid, reason) {
|
||||||
const warning = new Error('Unhandled promise rejection ' +
|
const warning = new Error(
|
||||||
`(rejection id: ${uid}): ${String(reason)}`);
|
`Unhandled promise rejection (rejection id: ${uid}): ` +
|
||||||
|
safeToString(reason));
|
||||||
warning.name = 'UnhandledPromiseRejectionWarning';
|
warning.name = 'UnhandledPromiseRejectionWarning';
|
||||||
warning.id = uid;
|
warning.id = uid;
|
||||||
if (reason instanceof Error) {
|
try {
|
||||||
warning.stack = reason.stack;
|
if (reason instanceof Error) {
|
||||||
|
warning.stack = reason.stack;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
// ignored
|
||||||
}
|
}
|
||||||
process.emitWarning(warning);
|
process.emitWarning(warning);
|
||||||
if (!deprecationWarned) {
|
if (!deprecationWarned) {
|
||||||
|
@ -84,6 +84,12 @@ static void GetProxyDetails(const FunctionCallbackInfo<Value>& args) {
|
|||||||
args.GetReturnValue().Set(ret);
|
args.GetReturnValue().Set(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Side effect-free stringification that will never throw exceptions.
|
||||||
|
static void SafeToString(const FunctionCallbackInfo<Value>& args) {
|
||||||
|
auto context = args.GetIsolate()->GetCurrentContext();
|
||||||
|
args.GetReturnValue().Set(args[0]->ToDetailString(context).ToLocalChecked());
|
||||||
|
}
|
||||||
|
|
||||||
inline Local<Private> IndexToPrivateSymbol(Environment* env, uint32_t index) {
|
inline Local<Private> IndexToPrivateSymbol(Environment* env, uint32_t index) {
|
||||||
#define V(name, _) &Environment::name,
|
#define V(name, _) &Environment::name,
|
||||||
static Local<Private> (Environment::*const methods[])() const = {
|
static Local<Private> (Environment::*const methods[])() const = {
|
||||||
@ -221,6 +227,7 @@ void Initialize(Local<Object> target,
|
|||||||
env->SetMethod(target, "setHiddenValue", SetHiddenValue);
|
env->SetMethod(target, "setHiddenValue", SetHiddenValue);
|
||||||
env->SetMethod(target, "getPromiseDetails", GetPromiseDetails);
|
env->SetMethod(target, "getPromiseDetails", GetPromiseDetails);
|
||||||
env->SetMethod(target, "getProxyDetails", GetProxyDetails);
|
env->SetMethod(target, "getProxyDetails", GetProxyDetails);
|
||||||
|
env->SetMethod(target, "safeToString", SafeToString);
|
||||||
|
|
||||||
env->SetMethod(target, "startSigintWatchdog", StartSigintWatchdog);
|
env->SetMethod(target, "startSigintWatchdog", StartSigintWatchdog);
|
||||||
env->SetMethod(target, "stopSigintWatchdog", StopSigintWatchdog);
|
env->SetMethod(target, "stopSigintWatchdog", StopSigintWatchdog);
|
||||||
|
38
test/parallel/test-promises-unhandled-proxy-rejections.js
Normal file
38
test/parallel/test-promises-unhandled-proxy-rejections.js
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
'use strict';
|
||||||
|
const common = require('../common');
|
||||||
|
|
||||||
|
const expectedDeprecationWarning = 'Unhandled promise rejections are ' +
|
||||||
|
'deprecated. In the future, promise ' +
|
||||||
|
'rejections that are not handled will ' +
|
||||||
|
'terminate the Node.js process with a ' +
|
||||||
|
'non-zero exit code.';
|
||||||
|
const expectedPromiseWarning = 'Unhandled promise rejection (rejection id: ' +
|
||||||
|
'1): [object Object]';
|
||||||
|
|
||||||
|
function throwErr() {
|
||||||
|
throw new Error('Error from proxy');
|
||||||
|
}
|
||||||
|
|
||||||
|
const thorny = new Proxy({}, {
|
||||||
|
getPrototypeOf: throwErr,
|
||||||
|
setPrototypeOf: throwErr,
|
||||||
|
isExtensible: throwErr,
|
||||||
|
preventExtensions: throwErr,
|
||||||
|
getOwnPropertyDescriptor: throwErr,
|
||||||
|
defineProperty: throwErr,
|
||||||
|
has: throwErr,
|
||||||
|
get: throwErr,
|
||||||
|
set: throwErr,
|
||||||
|
deleteProperty: throwErr,
|
||||||
|
ownKeys: throwErr,
|
||||||
|
apply: throwErr,
|
||||||
|
construct: throwErr
|
||||||
|
});
|
||||||
|
|
||||||
|
common.expectWarning({
|
||||||
|
DeprecationWarning: expectedDeprecationWarning,
|
||||||
|
UnhandledPromiseRejectionWarning: expectedPromiseWarning,
|
||||||
|
});
|
||||||
|
|
||||||
|
// ensure this doesn't crash
|
||||||
|
Promise.reject(thorny);
|
Loading…
x
Reference in New Issue
Block a user