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 {
|
||||
std::vector<double> 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) {
|
||||
// Want each callback to be cleaned up after itself, instead of cleaning
|
||||
// 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) {
|
||||
AsyncHooks* async_hooks = env->async_hooks();
|
||||
|
||||
if (async_hooks->fields()[type] == 0)
|
||||
if (async_hooks->fields()[type] == 0 || !env->can_call_into_js())
|
||||
return;
|
||||
|
||||
v8::HandleScope handle_scope(env->isolate());
|
||||
@ -625,8 +626,10 @@ void AsyncWrap::EmitTraceEventDestroy() {
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (env->destroy_async_id_list()->empty()) {
|
||||
env->SetUnrefImmediate(DestroyAsyncIdsCallback, nullptr);
|
||||
|
@ -559,6 +559,14 @@ void Environment::SetUnrefImmediate(native_immediate_callback cb,
|
||||
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() {
|
||||
return performance_state_.get();
|
||||
}
|
||||
|
@ -679,6 +679,12 @@ class Environment {
|
||||
const char* path = 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 ThrowTypeError(const char* errmsg);
|
||||
inline void ThrowRangeError(const char* errmsg);
|
||||
@ -821,6 +827,7 @@ class Environment {
|
||||
|
||||
std::unique_ptr<performance::performance_state> performance_state_;
|
||||
std::unordered_map<std::string, uint64_t> performance_marks_;
|
||||
bool can_call_into_js_ = true;
|
||||
|
||||
#if HAVE_INSPECTOR
|
||||
std::unique_ptr<inspector::Agent> inspector_agent_;
|
||||
|
@ -954,6 +954,11 @@ InternalCallbackScope::InternalCallbackScope(Environment* env,
|
||||
CHECK(!object.IsEmpty());
|
||||
}
|
||||
|
||||
if (!env->can_call_into_js()) {
|
||||
failed_ = true;
|
||||
return;
|
||||
}
|
||||
|
||||
HandleScope handle_scope(env->isolate());
|
||||
// If you hit this assertion, you forgot to enter the v8::Context first.
|
||||
CHECK_EQ(Environment::GetCurrent(env->isolate()), env);
|
||||
@ -997,6 +1002,7 @@ void InternalCallbackScope::Close() {
|
||||
|
||||
Environment::TickInfo* tick_info = env_->tick_info();
|
||||
|
||||
if (!env_->can_call_into_js()) return;
|
||||
if (!tick_info->has_scheduled()) {
|
||||
env_->isolate()->RunMicrotasks();
|
||||
}
|
||||
@ -1014,6 +1020,8 @@ void InternalCallbackScope::Close() {
|
||||
|
||||
Local<Object> process = env_->process_object();
|
||||
|
||||
if (!env_->can_call_into_js()) return;
|
||||
|
||||
if (env_->tick_callback_function()->Call(process, 0, nullptr).IsEmpty()) {
|
||||
env_->tick_info()->set_has_thrown(true);
|
||||
failed_ = true;
|
||||
@ -4552,6 +4560,7 @@ inline int Start(Isolate* isolate, IsolateData* isolate_data,
|
||||
|
||||
WaitForInspectorDisconnect(&env);
|
||||
|
||||
env.set_can_call_into_js(false);
|
||||
env.RunCleanup();
|
||||
RunAtExit(&env);
|
||||
|
||||
|
@ -820,6 +820,8 @@ class ContextifyScript : public BaseObject {
|
||||
const bool display_errors,
|
||||
const bool break_on_sigint,
|
||||
const FunctionCallbackInfo<Value>& args) {
|
||||
if (!env->can_call_into_js())
|
||||
return false;
|
||||
if (!ContextifyScript::InstanceOf(env, args.Holder())) {
|
||||
env->ThrowTypeError(
|
||||
"Script methods can only be called on script instances.");
|
||||
|
Loading…
x
Reference in New Issue
Block a user