From 37501aa32357e75b9ddc92198da94d92fcdd0798 Mon Sep 17 00:00:00 2001 From: Nathan Whitaker <17734409+nathanwhit@users.noreply.github.com> Date: Wed, 28 Aug 2024 13:42:42 -0700 Subject: [PATCH] fix(napi): Don't run microtasks in napi_resolve_deferred (#25246) Fixes an incredibly obscure bug that causes parcel's file watcher to not get any file update notifications on macOS. The issue was that the native addon was calling `napi_resolve_deferred`, but when we resolved the promise, v8 was running microtasks automatically. That executed JS, which called back into the native addon and broke the addon's assumption that the call wouldn't be reentrant. --- cli/napi/js_native_api.rs | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/cli/napi/js_native_api.rs b/cli/napi/js_native_api.rs index 5269d8d1d3..e922d8c3f2 100644 --- a/cli/napi/js_native_api.rs +++ b/cli/napi/js_native_api.rs @@ -3307,19 +3307,30 @@ fn napi_resolve_deferred( check_arg!(env, result); check_arg!(env, deferred); + // Make sure microtasks don't run and call back into JS + env + .scope() + .set_microtasks_policy(v8::MicrotasksPolicy::Explicit); + let deferred_ptr = unsafe { NonNull::new_unchecked(deferred as *mut v8::PromiseResolver) }; let global = unsafe { v8::Global::from_raw(env.isolate(), deferred_ptr) }; let resolver = v8::Local::new(&mut env.scope(), global); - if !resolver + let success = resolver .resolve(&mut env.scope(), result.unwrap()) - .unwrap_or(false) - { - return napi_generic_failure; - } + .unwrap_or(false); - napi_ok + // Restore policy + env + .scope() + .set_microtasks_policy(v8::MicrotasksPolicy::Auto); + + if success { + napi_ok + } else { + napi_generic_failure + } } #[napi_sym]