From c9384a609e66a97403fdcdd3add74581e03c0401 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Tue, 5 Mar 2024 00:00:39 +0900 Subject: [PATCH] chore: update src_preload_function_for_environment.patch (#41501) --- patches/node/.patches | 2 +- ...src_preload_function_for_environment.patch | 244 ++++++++---------- shell/app/node_main.cc | 5 +- shell/common/node_bindings.cc | 5 +- 4 files changed, 119 insertions(+), 137 deletions(-) diff --git a/patches/node/.patches b/patches/node/.patches index 66a1637f3f4e1..afb647d567e24 100644 --- a/patches/node/.patches +++ b/patches/node/.patches @@ -50,5 +50,5 @@ src_update_default_v8_platform_to_override_functions_with_location.patch fix_capture_embedder_exceptions_before_entering_v8.patch spec_add_iterator_to_global_intrinsics.patch fix_undici_incorrectly_copies_headers_onto_fetches.patch -src_preload_function_for_environment.patch fix_revert_src_lb_reducing_c_calls_of_esm_legacy_main_resolve.patch +src_preload_function_for_environment.patch diff --git a/patches/node/src_preload_function_for_environment.patch b/patches/node/src_preload_function_for_environment.patch index 9c1ea7fa4a44c..52a70f2a2e2e1 100644 --- a/patches/node/src_preload_function_for_environment.patch +++ b/patches/node/src_preload_function_for_environment.patch @@ -1,23 +1,9 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Cheng Zhao -Date: Mon, 22 Jan 2024 13:45:55 +0900 +Date: Mon, 4 Mar 2024 11:41:18 +0900 Subject: src: preload function for Environment -https://github.com/nodejs/node/pull/51539 - -This PR adds a |preload| arg to the node::CreateEnvironment to allow -embedders to set a preload function for the environment, which will run -after the environment is loaded and before the main script runs. - -This is similiar to the --require CLI option, but runs a C++ function, -and can only be set by embedders. - -The preload function can be used by embedders to inject scripts before -running the main script, for example: -1. In Electron it is used to initialize the ASAR virtual filesystem, - inject custom process properties, etc. -2. In VS Code it can be used to reset the module search paths for - extensions. +Backport https://github.com/nodejs/node/pull/51539 diff --git a/lib/internal/process/pre_execution.js b/lib/internal/process/pre_execution.js index cbb89d76621de6a85b8e8697078d74c6bde0a742..4b1c0405a3bc7fb66d138b273cab05589b1a7360 100644 @@ -45,92 +31,80 @@ index cbb89d76621de6a85b8e8697078d74c6bde0a742..4b1c0405a3bc7fb66d138b273cab0558 // For user code, we preload modules if `-r` is passed const preloadModules = getOptionValue('--require'); diff --git a/src/api/environment.cc b/src/api/environment.cc -index 74b4e15b8230c6380d41e84aa504824bb79b2ee5..e033760193fcd4fedd645c9259f58bc6b06250f4 100644 +index 74b4e15b8230c6380d41e84aa504824bb79b2ee5..5ef231ba77b187ff4df3b3d2f3f4eec2b7667c92 100644 --- a/src/api/environment.cc +++ b/src/api/environment.cc -@@ -437,7 +437,8 @@ Environment* CreateEnvironment( - const std::vector& exec_args, - EnvironmentFlags::Flags flags, - ThreadId thread_id, -- std::unique_ptr inspector_parent_handle) { -+ std::unique_ptr inspector_parent_handle, -+ EmbedderPreloadCallback preload) { - Isolate* isolate = isolate_data->isolate(); - HandleScope handle_scope(isolate); +@@ -549,25 +549,31 @@ NODE_EXTERN std::unique_ptr GetInspectorParentHandle( + #endif + } -@@ -456,7 +457,8 @@ Environment* CreateEnvironment( - exec_args, - env_snapshot_info, - flags, -- thread_id); -+ thread_id, -+ std::move(preload)); - CHECK_NOT_NULL(env); +-MaybeLocal LoadEnvironment( +- Environment* env, +- StartExecutionCallback cb) { ++MaybeLocal LoadEnvironment(Environment* env, ++ StartExecutionCallback cb, ++ EmbedderPreloadCallback preload) { + env->InitializeLibuv(); + env->InitializeDiagnostics(); ++ if (preload) { ++ env->set_embedder_preload(std::move(preload)); ++ } - if (use_snapshot) { + return StartExecution(env, cb); + } + + MaybeLocal LoadEnvironment(Environment* env, +- std::string_view main_script_source_utf8) { ++ std::string_view main_script_source_utf8, ++ EmbedderPreloadCallback preload) { + CHECK_NOT_NULL(main_script_source_utf8.data()); + return LoadEnvironment( +- env, [&](const StartExecutionCallbackInfo& info) -> MaybeLocal { ++ env, ++ [&](const StartExecutionCallbackInfo& info) -> MaybeLocal { + Local main_script = + ToV8Value(env->context(), main_script_source_utf8).ToLocalChecked(); + return info.run_cjs->Call( + env->context(), Null(env->isolate()), 1, &main_script); +- }); ++ }, ++ std::move(preload)); + } + + Environment* GetCurrentEnvironment(Local context) { diff --git a/src/env-inl.h b/src/env-inl.h -index 524a9633ef16e48797dc6a1e507ca0be2bfffe7e..b5ec98128d4e08ef26121be070ac2ebe5e339534 100644 +index 524a9633ef16e48797dc6a1e507ca0be2bfffe7e..9f30ebb821dfcbfe4c7c55332a28d076b09b9177 100644 --- a/src/env-inl.h +++ b/src/env-inl.h -@@ -438,6 +438,10 @@ inline void Environment::set_embedder_entry_point(StartExecutionCallback&& fn) { +@@ -438,6 +438,14 @@ inline void Environment::set_embedder_entry_point(StartExecutionCallback&& fn) { embedder_entry_point_ = std::move(fn); } +inline const EmbedderPreloadCallback& Environment::embedder_preload() const { + return embedder_preload_; +} ++ ++inline void Environment::set_embedder_preload(EmbedderPreloadCallback fn) { ++ embedder_preload_ = std::move(fn); ++} + inline double Environment::new_async_id() { async_hooks()->async_id_fields()[AsyncHooks::kAsyncIdCounter] += 1; return async_hooks()->async_id_fields()[AsyncHooks::kAsyncIdCounter]; -diff --git a/src/env.cc b/src/env.cc -index 25b81dee18aeeb1bd0452ba0b66085d451723709..1b4e783ca1f4ac6e09ce9fc1caad30de85e3be91 100644 ---- a/src/env.cc -+++ b/src/env.cc -@@ -763,7 +763,8 @@ Environment::Environment(IsolateData* isolate_data, - const std::vector& exec_args, - const EnvSerializeInfo* env_info, - EnvironmentFlags::Flags flags, -- ThreadId thread_id) -+ ThreadId thread_id, -+ EmbedderPreloadCallback preload) - : isolate_(isolate), - isolate_data_(isolate_data), - async_hooks_(isolate, MAYBE_FIELD_PTR(env_info, async_hooks)), -@@ -789,7 +790,8 @@ Environment::Environment(IsolateData* isolate_data, - flags_(flags), - thread_id_(thread_id.id == static_cast(-1) - ? AllocateEnvironmentThreadId().id -- : thread_id.id) { -+ : thread_id.id), -+ embedder_preload_(std::move(preload)) { - constexpr bool is_shared_ro_heap = - #ifdef NODE_V8_SHARED_RO_HEAP - true; diff --git a/src/env.h b/src/env.h -index 448075e354c760a2dbd1dd763f40b7a645730250..a5aad9596953536b0a1f741dfbc4f21f6a961404 100644 +index 448075e354c760a2dbd1dd763f40b7a645730250..d6956873b1b7bdf49ed0217587729aaa974ae89f 100644 --- a/src/env.h +++ b/src/env.h -@@ -635,7 +635,8 @@ class Environment : public MemoryRetainer { - const std::vector& exec_args, - const EnvSerializeInfo* env_info, - EnvironmentFlags::Flags flags, -- ThreadId thread_id); -+ ThreadId thread_id, -+ EmbedderPreloadCallback preload); - void InitializeMainContext(v8::Local context, - const EnvSerializeInfo* env_info); - ~Environment() override; -@@ -986,6 +987,8 @@ class Environment : public MemoryRetainer { +@@ -985,6 +985,8 @@ class Environment : public MemoryRetainer { + inline const StartExecutionCallback& embedder_entry_point() const; inline void set_embedder_entry_point(StartExecutionCallback&& fn); - + inline const EmbedderPreloadCallback& embedder_preload() const; -+ ++ inline void set_embedder_preload(EmbedderPreloadCallback fn); + inline void set_process_exit_handler( std::function&& handler); - -@@ -1186,6 +1189,7 @@ class Environment : public MemoryRetainer { +@@ -1186,6 +1188,7 @@ class Environment : public MemoryRetainer { builtins::BuiltinLoader builtin_loader_; StartExecutionCallback embedder_entry_point_; @@ -139,43 +113,45 @@ index 448075e354c760a2dbd1dd763f40b7a645730250..a5aad9596953536b0a1f741dfbc4f21f // Used by allocate_managed_buffer() and release_managed_buffer() to keep // track of the BackingStore for a given pointer. diff --git a/src/node.h b/src/node.h -index 3ffc51783b0b6dee1c0f0a37d2f52cb1aec2fa3f..4d88bbedb2fc2776d32cbaa755fd8657f17f78bc 100644 +index 3ffc51783b0b6dee1c0f0a37d2f52cb1aec2fa3f..400a6b91ccb9875352012bffc21bc842f6febb9c 100644 --- a/src/node.h +++ b/src/node.h -@@ -676,11 +676,23 @@ struct InspectorParentHandle { - virtual ~InspectorParentHandle() = default; - }; +@@ -716,12 +716,33 @@ struct StartExecutionCallbackInfo { + using StartExecutionCallback = + std::function(const StartExecutionCallbackInfo&)>; +using EmbedderPreloadCallback = + std::function process, + v8::Local require)>; -+ - // TODO(addaleax): Maybe move per-Environment options parsing here. - // Returns nullptr when the Environment cannot be created e.g. there are - // pending JavaScript exceptions. - // `context` may be empty if an `EmbedderSnapshotData` instance was provided - // to `NewIsolate()` and `CreateIsolateData()`. + ++// Run initialization for the environment. +// -+// The |preload| function will run before executing the entry point, which -+// is usually used by embedders to inject scripts. The function is executed -+// with preload(process, require), and the passed require function has access -+// to internal Node.js modules. The |preload| function is inherited by worker -+// threads and thus will run in work threads, so make sure the function is -+// thread-safe. - NODE_EXTERN Environment* CreateEnvironment( - IsolateData* isolate_data, - v8::Local context, -@@ -688,7 +700,8 @@ NODE_EXTERN Environment* CreateEnvironment( - const std::vector& exec_args, - EnvironmentFlags::Flags flags = EnvironmentFlags::kDefaultFlags, - ThreadId thread_id = {} /* allocates a thread id automatically */, -- std::unique_ptr inspector_parent_handle = {}); -+ std::unique_ptr inspector_parent_handle = {}, ++// The |preload| function, usually used by embedders to inject scripts, ++// will be run by Node.js before Node.js executes the entry point. ++// The function is guaranteed to run before the user land module loader running ++// any user code, so it is safe to assume that at this point, no user code has ++// been run yet. ++// The function will be executed with preload(process, require), and the passed ++// require function has access to internal Node.js modules. There is no ++// stability guarantee about the internals exposed to the internal require ++// function. Expect breakages when updating Node.js versions if the embedder ++// imports internal modules with the internal require function. ++// Worker threads created in the environment will also respect The |preload| ++// function, so make sure the function is thread-safe. + NODE_EXTERN v8::MaybeLocal LoadEnvironment( + Environment* env, +- StartExecutionCallback cb); ++ StartExecutionCallback cb, ++ EmbedderPreloadCallback preload = nullptr); + NODE_EXTERN v8::MaybeLocal LoadEnvironment( +- Environment* env, std::string_view main_script_source_utf8); ++ Environment* env, ++ std::string_view main_script_source_utf8, + EmbedderPreloadCallback preload = nullptr); + NODE_EXTERN void FreeEnvironment(Environment* env); - // Returns a handle that can be passed to `LoadEnvironment()`, making the - // child Environment accessible to the inspector as if it were a Node.js Worker. + // Set a callback that is called when process.exit() is called from JS, diff --git a/src/node_options.cc b/src/node_options.cc index 6eb2c137e1dd05b05e781820905cf6778107275d..b098837338c2c0d435ee8e659433f168c453dde5 100644 --- a/src/node_options.cc @@ -194,24 +170,28 @@ index 6eb2c137e1dd05b05e781820905cf6778107275d..b098837338c2c0d435ee8e659433f168 } diff --git a/src/node_snapshotable.cc b/src/node_snapshotable.cc -index 562a47ddcc9c8e61590b7b09d84dc08ab4b3653d..325bebc1df9ad2e8b0bad468951cf1563ecefc14 100644 +index 562a47ddcc9c8e61590b7b09d84dc08ab4b3653d..431cbe1c2cb77669ceb10602a7b3ef1c2f7e8718 100644 --- a/src/node_snapshotable.cc +++ b/src/node_snapshotable.cc -@@ -1369,6 +1369,13 @@ static void RunEmbedderEntryPoint(const FunctionCallbackInfo& args) { +@@ -1369,6 +1369,17 @@ static void RunEmbedderEntryPoint(const FunctionCallbackInfo& args) { } } -+static void RunEmbedderPreload(const FunctionCallbackInfo& args) { ++void RunEmbedderPreload(const FunctionCallbackInfo& args) { + Environment* env = Environment::GetCurrent(args); + CHECK(env->embedder_preload()); + CHECK_EQ(args.Length(), 2); -+ env->embedder_preload()(env, args[0], args[1]); ++ Local process_obj = args[0]; ++ Local require_fn = args[1]; ++ CHECK(process_obj->IsObject()); ++ CHECK(require_fn->IsFunction()); ++ env->embedder_preload()(env, process_obj, require_fn); +} + void CompileSerializeMain(const FunctionCallbackInfo& args) { CHECK(args[0]->IsString()); Local filename = args[0].As(); -@@ -1493,6 +1500,7 @@ void CreatePerIsolateProperties(IsolateData* isolate_data, +@@ -1493,6 +1504,7 @@ void CreatePerIsolateProperties(IsolateData* isolate_data, Local target) { Isolate* isolate = isolate_data->isolate(); SetMethod(isolate, target, "runEmbedderEntryPoint", RunEmbedderEntryPoint); @@ -219,7 +199,7 @@ index 562a47ddcc9c8e61590b7b09d84dc08ab4b3653d..325bebc1df9ad2e8b0bad468951cf156 SetMethod(isolate, target, "compileSerializeMain", CompileSerializeMain); SetMethod(isolate, target, "setSerializeCallback", SetSerializeCallback); SetMethod(isolate, target, "setDeserializeCallback", SetDeserializeCallback); -@@ -1506,6 +1514,7 @@ void CreatePerIsolateProperties(IsolateData* isolate_data, +@@ -1506,6 +1518,7 @@ void CreatePerIsolateProperties(IsolateData* isolate_data, void RegisterExternalReferences(ExternalReferenceRegistry* registry) { registry->Register(RunEmbedderEntryPoint); @@ -228,7 +208,7 @@ index 562a47ddcc9c8e61590b7b09d84dc08ab4b3653d..325bebc1df9ad2e8b0bad468951cf156 registry->Register(SetSerializeCallback); registry->Register(SetDeserializeCallback); diff --git a/src/node_worker.cc b/src/node_worker.cc -index 900674bbe4c90e9aeb2013c06c9979864b06dcd5..2a22d986585e93ea00c6dcdca1f7b783ef0723f8 100644 +index 900674bbe4c90e9aeb2013c06c9979864b06dcd5..52d7473b05ccb49e5fc915224b6d2972a14191da 100644 --- a/src/node_worker.cc +++ b/src/node_worker.cc @@ -63,6 +63,7 @@ Worker::Worker(Environment* env, @@ -239,16 +219,20 @@ index 900674bbe4c90e9aeb2013c06c9979864b06dcd5..2a22d986585e93ea00c6dcdca1f7b783 snapshot_data_(snapshot_data) { Debug(this, "Creating new worker instance with thread id %llu", thread_id_.id); -@@ -360,7 +361,8 @@ void Worker::Run() { - std::move(exec_argv_), - static_cast(environment_flags_), - thread_id_, -- std::move(inspector_parent_handle_))); -+ std::move(inspector_parent_handle_), -+ std::move(embedder_preload_))); - if (is_stopped()) return; - CHECK_NOT_NULL(env_); - env_->set_env_vars(std::move(env_vars_)); +@@ -381,8 +382,12 @@ void Worker::Run() { + } + + Debug(this, "Created message port for worker %llu", thread_id_.id); +- if (LoadEnvironment(env_.get(), StartExecutionCallback{}).IsEmpty()) ++ if (LoadEnvironment(env_.get(), ++ StartExecutionCallback{}, ++ std::move(embedder_preload_)) ++ .IsEmpty()) { + return; ++ } + + Debug(this, "Loaded environment for worker %llu", thread_id_.id); + } diff --git a/src/node_worker.h b/src/node_worker.h index 531e2b5287010f9206ab4fd7f4dd0f3dec9fe55c..07fd7b460654e169e8b6822474dc3cc70fcec4c0 100644 --- a/src/node_worker.h @@ -262,7 +246,7 @@ index 531e2b5287010f9206ab4fd7f4dd0f3dec9fe55c..07fd7b460654e169e8b6822474dc3cc7 // A raw flag that is used by creator and worker threads to // sync up on pre-mature termination of worker - while in the diff --git a/test/cctest/test_environment.cc b/test/cctest/test_environment.cc -index 2e747c7be58922897abd0424b797f3f12a89ada1..658f8df4b01d60759e858cf5283b9be9467dd142 100644 +index 2e747c7be58922897abd0424b797f3f12a89ada1..fcffaca89cf5aa24be6e539bfb4d9d6df690a709 100644 --- a/test/cctest/test_environment.cc +++ b/test/cctest/test_environment.cc @@ -773,3 +773,31 @@ TEST_F(EnvironmentTest, RequestInterruptAtExit) { @@ -280,20 +264,20 @@ index 2e747c7be58922897abd0424b797f3f12a89ada1..658f8df4b01d60759e858cf5283b9be9 + v8::Local require) { + CHECK(process->IsObject()); + CHECK(require->IsFunction()); -+ process.As()->Set( -+ env->context(), -+ v8::String::NewFromUtf8Literal(env->isolate(), "prop"), -+ v8::String::NewFromUtf8Literal(env->isolate(), "preload")).Check(); ++ process.As() ++ ->Set(env->context(), ++ v8::String::NewFromUtf8Literal(env->isolate(), "prop"), ++ v8::String::NewFromUtf8Literal(env->isolate(), "preload")) ++ .Check(); + }; + + std::unique_ptr env( -+ node::CreateEnvironment(isolate_data_, context, {}, {}, -+ node::EnvironmentFlags::kDefaultFlags, {}, {}, -+ preload), ++ node::CreateEnvironment(isolate_data_, context, {}, {}), + node::FreeEnvironment); + + v8::Local main_ret = -+ node::LoadEnvironment(env.get(), "return process.prop;").ToLocalChecked(); ++ node::LoadEnvironment(env.get(), "return process.prop;", preload) ++ .ToLocalChecked(); + node::Utf8Value main_ret_str(isolate_, main_ret); + EXPECT_EQ(std::string(*main_ret_str), "preload"); +} diff --git a/shell/app/node_main.cc b/shell/app/node_main.cc index 20b70806500f2..1c96b02c35bc3 100644 --- a/shell/app/node_main.cc +++ b/shell/app/node_main.cc @@ -259,8 +259,7 @@ int NodeMain(int argc, char* argv[]) { env = node::CreateEnvironment( isolate_data, isolate->GetCurrentContext(), result->args(), result->exec_args(), - static_cast(env_flags), {}, {}, - &OnNodePreload); + static_cast(env_flags)); CHECK_NE(nullptr, env); node::SetIsolateUpForNode(isolate); @@ -285,7 +284,7 @@ int NodeMain(int argc, char* argv[]) { } v8::HandleScope scope(isolate); - node::LoadEnvironment(env, node::StartExecutionCallback{}); + node::LoadEnvironment(env, node::StartExecutionCallback{}, &OnNodePreload); // Potential reasons we get Nothing here may include: the env // is stopping, or the user hooks process.emit('exit'). diff --git a/shell/common/node_bindings.cc b/shell/common/node_bindings.cc index 73ef731a8ebaa..369b0e926336d 100644 --- a/shell/common/node_bindings.cc +++ b/shell/common/node_bindings.cc @@ -659,8 +659,7 @@ std::shared_ptr NodeBindings::CreateEnvironment( v8::TryCatch try_catch(isolate); env = node::CreateEnvironment( static_cast(isolate_data), context, args, exec_args, - static_cast(env_flags), {}, {}, - &OnNodePreload); + static_cast(env_flags)); if (try_catch.HasCaught()) { std::string err_msg = @@ -792,7 +791,7 @@ std::shared_ptr NodeBindings::CreateEnvironment( } void NodeBindings::LoadEnvironment(node::Environment* env) { - node::LoadEnvironment(env, node::StartExecutionCallback{}); + node::LoadEnvironment(env, node::StartExecutionCallback{}, &OnNodePreload); gin_helper::EmitEvent(env->isolate(), env->process_object(), "loaded"); }