src, lib: take control of prepareStackTrace
Refs https://crbug.com/v8/7848 PR-URL: https://github.com/nodejs/node/pull/23926 Reviewed-By: Refael Ackermann <refack@gmail.com> Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
This commit is contained in:
parent
9fec70a703
commit
b046bd1935
@ -35,6 +35,8 @@
|
|||||||
// passed by node::RunBootstrapping()
|
// passed by node::RunBootstrapping()
|
||||||
/* global process, require, internalBinding, isMainThread, ownsProcessState */
|
/* global process, require, internalBinding, isMainThread, ownsProcessState */
|
||||||
|
|
||||||
|
setupPrepareStackTrace();
|
||||||
|
|
||||||
const { JSON, Object, Symbol } = primordials;
|
const { JSON, Object, Symbol } = primordials;
|
||||||
const config = internalBinding('config');
|
const config = internalBinding('config');
|
||||||
const { deprecate } = require('internal/util');
|
const { deprecate } = require('internal/util');
|
||||||
@ -290,6 +292,12 @@ process.emitWarning = emitWarning;
|
|||||||
// Note: only after this point are the timers effective
|
// Note: only after this point are the timers effective
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setupPrepareStackTrace() {
|
||||||
|
const { setPrepareStackTraceCallback } = internalBinding('errors');
|
||||||
|
const { prepareStackTrace } = require('internal/errors');
|
||||||
|
setPrepareStackTraceCallback(prepareStackTrace);
|
||||||
|
}
|
||||||
|
|
||||||
function setupProcessObject() {
|
function setupProcessObject() {
|
||||||
const EventEmitter = require('events');
|
const EventEmitter = require('events');
|
||||||
const origProcProto = Object.getPrototypeOf(process);
|
const origProcProto = Object.getPrototypeOf(process);
|
||||||
|
@ -19,6 +19,31 @@ const codes = {};
|
|||||||
|
|
||||||
const { kMaxLength } = internalBinding('buffer');
|
const { kMaxLength } = internalBinding('buffer');
|
||||||
|
|
||||||
|
const MainContextError = Error;
|
||||||
|
const ErrorToString = Error.prototype.toString;
|
||||||
|
// Polyfill of V8's Error.prepareStackTrace API.
|
||||||
|
// https://crbug.com/v8/7848
|
||||||
|
const prepareStackTrace = (globalThis, error, trace) => {
|
||||||
|
// `globalThis` is the global that contains the constructor which
|
||||||
|
// created `error`.
|
||||||
|
if (typeof globalThis.Error.prepareStackTrace === 'function') {
|
||||||
|
return globalThis.Error.prepareStackTrace(error, trace);
|
||||||
|
}
|
||||||
|
// We still have legacy usage that depends on the main context's `Error`
|
||||||
|
// being used, even when the error is from a different context.
|
||||||
|
// TODO(devsnek): evaluate if this can be eventually deprecated/removed.
|
||||||
|
if (typeof MainContextError.prepareStackTrace === 'function') {
|
||||||
|
return MainContextError.prepareStackTrace(error, trace);
|
||||||
|
}
|
||||||
|
|
||||||
|
const errorString = ErrorToString.call(error);
|
||||||
|
if (trace.length === 0) {
|
||||||
|
return errorString;
|
||||||
|
}
|
||||||
|
return `${errorString}\n at ${trace.join('\n at ')}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
let excludedStackFn;
|
let excludedStackFn;
|
||||||
|
|
||||||
// Lazily loaded
|
// Lazily loaded
|
||||||
@ -598,7 +623,8 @@ module.exports = {
|
|||||||
uvExceptionWithHostPort,
|
uvExceptionWithHostPort,
|
||||||
SystemError,
|
SystemError,
|
||||||
// This is exported only to facilitate testing.
|
// This is exported only to facilitate testing.
|
||||||
E
|
E,
|
||||||
|
prepareStackTrace,
|
||||||
};
|
};
|
||||||
|
|
||||||
// To declare an error message, use the E(sym, val, def) function above. The sym
|
// To declare an error message, use the E(sym, val, def) function above. The sym
|
||||||
|
@ -13,6 +13,8 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace node {
|
namespace node {
|
||||||
|
using errors::TryCatchScope;
|
||||||
|
using v8::Array;
|
||||||
using v8::Context;
|
using v8::Context;
|
||||||
using v8::EscapableHandleScope;
|
using v8::EscapableHandleScope;
|
||||||
using v8::Function;
|
using v8::Function;
|
||||||
@ -45,6 +47,41 @@ static bool ShouldAbortOnUncaughtException(Isolate* isolate) {
|
|||||||
!env->inside_should_not_abort_on_uncaught_scope();
|
!env->inside_should_not_abort_on_uncaught_scope();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static MaybeLocal<Value> PrepareStackTraceCallback(Local<Context> context,
|
||||||
|
Local<Value> exception,
|
||||||
|
Local<Array> trace) {
|
||||||
|
Environment* env = Environment::GetCurrent(context);
|
||||||
|
if (env == nullptr) {
|
||||||
|
MaybeLocal<String> s = exception->ToString(context);
|
||||||
|
return s.IsEmpty() ?
|
||||||
|
MaybeLocal<Value>() :
|
||||||
|
MaybeLocal<Value>(s.ToLocalChecked());
|
||||||
|
}
|
||||||
|
Local<Function> prepare = env->prepare_stack_trace_callback();
|
||||||
|
if (prepare.IsEmpty()) {
|
||||||
|
MaybeLocal<String> s = exception->ToString(context);
|
||||||
|
return s.IsEmpty() ?
|
||||||
|
MaybeLocal<Value>() :
|
||||||
|
MaybeLocal<Value>(s.ToLocalChecked());
|
||||||
|
}
|
||||||
|
Local<Value> args[] = {
|
||||||
|
context->Global(),
|
||||||
|
exception,
|
||||||
|
trace,
|
||||||
|
};
|
||||||
|
// This TryCatch + Rethrow is required by V8 due to details around exception
|
||||||
|
// handling there. For C++ callbacks, V8 expects a scheduled exception (which
|
||||||
|
// is what ReThrow gives us). Just returning the empty MaybeLocal would leave
|
||||||
|
// us with a pending exception.
|
||||||
|
TryCatchScope try_catch(env);
|
||||||
|
MaybeLocal<Value> result = prepare->Call(
|
||||||
|
context, Undefined(env->isolate()), arraysize(args), args);
|
||||||
|
if (try_catch.HasCaught() && !try_catch.HasTerminated()) {
|
||||||
|
try_catch.ReThrow();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
void* NodeArrayBufferAllocator::Allocate(size_t size) {
|
void* NodeArrayBufferAllocator::Allocate(size_t size) {
|
||||||
if (zero_fill_field_ || per_process::cli_options->zero_fill_all_buffers)
|
if (zero_fill_field_ || per_process::cli_options->zero_fill_all_buffers)
|
||||||
return UncheckedCalloc(size);
|
return UncheckedCalloc(size);
|
||||||
@ -166,6 +203,7 @@ void SetIsolateUpForNode(v8::Isolate* isolate, IsolateSettingCategories cat) {
|
|||||||
isolate->SetAbortOnUncaughtExceptionCallback(
|
isolate->SetAbortOnUncaughtExceptionCallback(
|
||||||
ShouldAbortOnUncaughtException);
|
ShouldAbortOnUncaughtException);
|
||||||
isolate->SetFatalErrorHandler(OnFatalError);
|
isolate->SetFatalErrorHandler(OnFatalError);
|
||||||
|
isolate->SetPrepareStackTraceCallback(PrepareStackTraceCallback);
|
||||||
break;
|
break;
|
||||||
case IsolateSettingCategories::kMisc:
|
case IsolateSettingCategories::kMisc:
|
||||||
isolate->SetMicrotasksPolicy(MicrotasksPolicy::kExplicit);
|
isolate->SetMicrotasksPolicy(MicrotasksPolicy::kExplicit);
|
||||||
|
@ -402,6 +402,7 @@ constexpr size_t kFsStatsBufferLength = kFsStatsFieldsNumber * 2;
|
|||||||
V(native_module_require, v8::Function) \
|
V(native_module_require, v8::Function) \
|
||||||
V(performance_entry_callback, v8::Function) \
|
V(performance_entry_callback, v8::Function) \
|
||||||
V(performance_entry_template, v8::Function) \
|
V(performance_entry_template, v8::Function) \
|
||||||
|
V(prepare_stack_trace_callback, v8::Function) \
|
||||||
V(process_object, v8::Object) \
|
V(process_object, v8::Object) \
|
||||||
V(primordials, v8::Object) \
|
V(primordials, v8::Object) \
|
||||||
V(promise_reject_callback, v8::Function) \
|
V(promise_reject_callback, v8::Function) \
|
||||||
|
@ -48,6 +48,7 @@
|
|||||||
V(contextify) \
|
V(contextify) \
|
||||||
V(credentials) \
|
V(credentials) \
|
||||||
V(domain) \
|
V(domain) \
|
||||||
|
V(errors) \
|
||||||
V(fs) \
|
V(fs) \
|
||||||
V(fs_event_wrap) \
|
V(fs_event_wrap) \
|
||||||
V(heap_utils) \
|
V(heap_utils) \
|
||||||
|
@ -17,6 +17,7 @@ using v8::Boolean;
|
|||||||
using v8::Context;
|
using v8::Context;
|
||||||
using v8::Exception;
|
using v8::Exception;
|
||||||
using v8::Function;
|
using v8::Function;
|
||||||
|
using v8::FunctionCallbackInfo;
|
||||||
using v8::HandleScope;
|
using v8::HandleScope;
|
||||||
using v8::Int32;
|
using v8::Int32;
|
||||||
using v8::Isolate;
|
using v8::Isolate;
|
||||||
@ -767,6 +768,21 @@ void PerIsolateMessageListener(Local<Message> message, Local<Value> error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetPrepareStackTraceCallback(const FunctionCallbackInfo<Value>& args) {
|
||||||
|
Environment* env = Environment::GetCurrent(args);
|
||||||
|
CHECK(args[0]->IsFunction());
|
||||||
|
env->set_prepare_stack_trace_callback(args[0].As<Function>());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Initialize(Local<Object> target,
|
||||||
|
Local<Value> unused,
|
||||||
|
Local<Context> context,
|
||||||
|
void* priv) {
|
||||||
|
Environment* env = Environment::GetCurrent(context);
|
||||||
|
env->SetMethod(
|
||||||
|
target, "setPrepareStackTraceCallback", SetPrepareStackTraceCallback);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace errors
|
} // namespace errors
|
||||||
|
|
||||||
void DecorateErrorStack(Environment* env,
|
void DecorateErrorStack(Environment* env,
|
||||||
@ -880,3 +896,5 @@ void FatalException(Isolate* isolate,
|
|||||||
}
|
}
|
||||||
|
|
||||||
} // namespace node
|
} // namespace node
|
||||||
|
|
||||||
|
NODE_MODULE_CONTEXT_AWARE_INTERNAL(errors, node::errors::Initialize)
|
||||||
|
@ -9,6 +9,7 @@ const common = require('../common');
|
|||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
|
|
||||||
const expectedModules = new Set([
|
const expectedModules = new Set([
|
||||||
|
'Internal Binding errors',
|
||||||
'Internal Binding async_wrap',
|
'Internal Binding async_wrap',
|
||||||
'Internal Binding buffer',
|
'Internal Binding buffer',
|
||||||
'Internal Binding config',
|
'Internal Binding config',
|
||||||
|
Loading…
x
Reference in New Issue
Block a user