src: add can_call_into_js flag
This prevents calls back into JS from the shutdown phase. Many thanks for Stephen Belanger for reviewing the original version of this commit in the Ayo.js project. Refs: https://github.com/ayojs/ayo/pull/82 PR-URL: https://github.com/nodejs/node/pull/19377 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
parent
61fd027096
commit
bcb324c3ff
@ -141,6 +141,7 @@ static void DestroyAsyncIdsCallback(Environment* env, void* data) {
|
|||||||
do {
|
do {
|
||||||
std::vector<double> destroy_async_id_list;
|
std::vector<double> destroy_async_id_list;
|
||||||
destroy_async_id_list.swap(*env->destroy_async_id_list());
|
destroy_async_id_list.swap(*env->destroy_async_id_list());
|
||||||
|
if (!env->can_call_into_js()) return;
|
||||||
for (auto async_id : destroy_async_id_list) {
|
for (auto async_id : destroy_async_id_list) {
|
||||||
// Want each callback to be cleaned up after itself, instead of cleaning
|
// Want each callback to be cleaned up after itself, instead of cleaning
|
||||||
// them all up after the while() loop completes.
|
// them all up after the while() loop completes.
|
||||||
@ -166,7 +167,7 @@ void Emit(Environment* env, double async_id, AsyncHooks::Fields type,
|
|||||||
Local<Function> fn) {
|
Local<Function> fn) {
|
||||||
AsyncHooks* async_hooks = env->async_hooks();
|
AsyncHooks* async_hooks = env->async_hooks();
|
||||||
|
|
||||||
if (async_hooks->fields()[type] == 0)
|
if (async_hooks->fields()[type] == 0 || !env->can_call_into_js())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
v8::HandleScope handle_scope(env->isolate());
|
v8::HandleScope handle_scope(env->isolate());
|
||||||
@ -625,8 +626,10 @@ void AsyncWrap::EmitTraceEventDestroy() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AsyncWrap::EmitDestroy(Environment* env, double async_id) {
|
void AsyncWrap::EmitDestroy(Environment* env, double async_id) {
|
||||||
if (env->async_hooks()->fields()[AsyncHooks::kDestroy] == 0)
|
if (env->async_hooks()->fields()[AsyncHooks::kDestroy] == 0 ||
|
||||||
|
!env->can_call_into_js()) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (env->destroy_async_id_list()->empty()) {
|
if (env->destroy_async_id_list()->empty()) {
|
||||||
env->SetUnrefImmediate(DestroyAsyncIdsCallback, nullptr);
|
env->SetUnrefImmediate(DestroyAsyncIdsCallback, nullptr);
|
||||||
|
@ -559,6 +559,14 @@ void Environment::SetUnrefImmediate(native_immediate_callback cb,
|
|||||||
CreateImmediate(cb, data, obj, false);
|
CreateImmediate(cb, data, obj, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool Environment::can_call_into_js() const {
|
||||||
|
return can_call_into_js_;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Environment::set_can_call_into_js(bool can_call_into_js) {
|
||||||
|
can_call_into_js_ = can_call_into_js;
|
||||||
|
}
|
||||||
|
|
||||||
inline performance::performance_state* Environment::performance_state() {
|
inline performance::performance_state* Environment::performance_state() {
|
||||||
return performance_state_.get();
|
return performance_state_.get();
|
||||||
}
|
}
|
||||||
|
@ -679,6 +679,12 @@ class Environment {
|
|||||||
const char* path = nullptr,
|
const char* path = nullptr,
|
||||||
const char* dest = nullptr);
|
const char* dest = nullptr);
|
||||||
|
|
||||||
|
// If this flag is set, calls into JS (if they would be observable
|
||||||
|
// from userland) must be avoided. This flag does not indicate whether
|
||||||
|
// calling into JS is allowed from a VM perspective at this point.
|
||||||
|
inline bool can_call_into_js() const;
|
||||||
|
inline void set_can_call_into_js(bool can_call_into_js);
|
||||||
|
|
||||||
inline void ThrowError(const char* errmsg);
|
inline void ThrowError(const char* errmsg);
|
||||||
inline void ThrowTypeError(const char* errmsg);
|
inline void ThrowTypeError(const char* errmsg);
|
||||||
inline void ThrowRangeError(const char* errmsg);
|
inline void ThrowRangeError(const char* errmsg);
|
||||||
@ -821,6 +827,7 @@ class Environment {
|
|||||||
|
|
||||||
std::unique_ptr<performance::performance_state> performance_state_;
|
std::unique_ptr<performance::performance_state> performance_state_;
|
||||||
std::unordered_map<std::string, uint64_t> performance_marks_;
|
std::unordered_map<std::string, uint64_t> performance_marks_;
|
||||||
|
bool can_call_into_js_ = true;
|
||||||
|
|
||||||
#if HAVE_INSPECTOR
|
#if HAVE_INSPECTOR
|
||||||
std::unique_ptr<inspector::Agent> inspector_agent_;
|
std::unique_ptr<inspector::Agent> inspector_agent_;
|
||||||
|
@ -954,6 +954,11 @@ InternalCallbackScope::InternalCallbackScope(Environment* env,
|
|||||||
CHECK(!object.IsEmpty());
|
CHECK(!object.IsEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!env->can_call_into_js()) {
|
||||||
|
failed_ = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
HandleScope handle_scope(env->isolate());
|
HandleScope handle_scope(env->isolate());
|
||||||
// If you hit this assertion, you forgot to enter the v8::Context first.
|
// If you hit this assertion, you forgot to enter the v8::Context first.
|
||||||
CHECK_EQ(Environment::GetCurrent(env->isolate()), env);
|
CHECK_EQ(Environment::GetCurrent(env->isolate()), env);
|
||||||
@ -997,6 +1002,7 @@ void InternalCallbackScope::Close() {
|
|||||||
|
|
||||||
Environment::TickInfo* tick_info = env_->tick_info();
|
Environment::TickInfo* tick_info = env_->tick_info();
|
||||||
|
|
||||||
|
if (!env_->can_call_into_js()) return;
|
||||||
if (!tick_info->has_scheduled()) {
|
if (!tick_info->has_scheduled()) {
|
||||||
env_->isolate()->RunMicrotasks();
|
env_->isolate()->RunMicrotasks();
|
||||||
}
|
}
|
||||||
@ -1014,6 +1020,8 @@ void InternalCallbackScope::Close() {
|
|||||||
|
|
||||||
Local<Object> process = env_->process_object();
|
Local<Object> process = env_->process_object();
|
||||||
|
|
||||||
|
if (!env_->can_call_into_js()) return;
|
||||||
|
|
||||||
if (env_->tick_callback_function()->Call(process, 0, nullptr).IsEmpty()) {
|
if (env_->tick_callback_function()->Call(process, 0, nullptr).IsEmpty()) {
|
||||||
env_->tick_info()->set_has_thrown(true);
|
env_->tick_info()->set_has_thrown(true);
|
||||||
failed_ = true;
|
failed_ = true;
|
||||||
@ -4552,6 +4560,7 @@ inline int Start(Isolate* isolate, IsolateData* isolate_data,
|
|||||||
|
|
||||||
WaitForInspectorDisconnect(&env);
|
WaitForInspectorDisconnect(&env);
|
||||||
|
|
||||||
|
env.set_can_call_into_js(false);
|
||||||
env.RunCleanup();
|
env.RunCleanup();
|
||||||
RunAtExit(&env);
|
RunAtExit(&env);
|
||||||
|
|
||||||
|
@ -820,6 +820,8 @@ class ContextifyScript : public BaseObject {
|
|||||||
const bool display_errors,
|
const bool display_errors,
|
||||||
const bool break_on_sigint,
|
const bool break_on_sigint,
|
||||||
const FunctionCallbackInfo<Value>& args) {
|
const FunctionCallbackInfo<Value>& args) {
|
||||||
|
if (!env->can_call_into_js())
|
||||||
|
return false;
|
||||||
if (!ContextifyScript::InstanceOf(env, args.Holder())) {
|
if (!ContextifyScript::InstanceOf(env, args.Holder())) {
|
||||||
env->ThrowTypeError(
|
env->ThrowTypeError(
|
||||||
"Script methods can only be called on script instances.");
|
"Script methods can only be called on script instances.");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user