From 218ce26e7f1d5081ed1667f626e3c5c9276996ba Mon Sep 17 00:00:00 2001 From: Archkon <180910180+Archkon@users.noreply.github.com> Date: Thu, 6 Aug 2026 14:13:48 +0800 Subject: [PATCH] process: fix experimental warning tracking Return Just(false) for duplicate experimental warnings and only record a warning after it has been emitted successfully. Signed-off-by: Archkon <180910180+Archkon@users.noreply.github.com> --- src/node_debug.h | 2 +- src/node_process-inl.h | 2 +- src/node_process_events.cc | 9 +++-- test/cctest/test_environment.cc | 63 +++++++++++++++++++++++++++++++++ 4 files changed, 71 insertions(+), 5 deletions(-) diff --git a/src/node_debug.h b/src/node_debug.h index 14dc033fe3ca..48317da977eb 100644 --- a/src/node_debug.h +++ b/src/node_debug.h @@ -3,7 +3,7 @@ #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS #ifdef DEBUG -#include "util.h" +#include "util-inl.h" #endif // DEBUG namespace node { diff --git a/src/node_process-inl.h b/src/node_process-inl.h index 21a448cfdb2a..ec7f94ed30fa 100644 --- a/src/node_process-inl.h +++ b/src/node_process-inl.h @@ -16,7 +16,7 @@ inline v8::Maybe ProcessEmitWarning(Environment* env, Args&&... args) { std::string warning = SPrintF(fmt, std::forward(args)...); - return ProcessEmitWarningGeneric(env, warning.c_str()); + return ProcessEmitWarningGeneric(env, warning); } } // namespace node diff --git a/src/node_process_events.cc b/src/node_process_events.cc index aac8d5bcbd31..ddc5ff7007ee 100644 --- a/src/node_process_events.cc +++ b/src/node_process_events.cc @@ -114,12 +114,15 @@ std::set experimental_warnings; Maybe ProcessEmitExperimentalWarning(Environment* env, const std::string& warning) { - if (experimental_warnings.contains(warning)) return Nothing(); + if (experimental_warnings.contains(warning)) return Just(false); - experimental_warnings.insert(warning); std::string message(warning); message.append(" is an experimental feature and might change at any time"); - return ProcessEmitWarningGeneric(env, message.c_str(), "ExperimentalWarning"); + Maybe emitted = + ProcessEmitWarningGeneric(env, message, "ExperimentalWarning"); + + if (emitted.FromMaybe(false)) experimental_warnings.insert(warning); + return emitted; } Maybe ProcessEmitDeprecationWarning(Environment* env, diff --git a/test/cctest/test_environment.cc b/test/cctest/test_environment.cc index 59c71835499e..ae577b8ce9ab 100644 --- a/test/cctest/test_environment.cc +++ b/test/cctest/test_environment.cc @@ -1,6 +1,7 @@ #include "libplatform/libplatform.h" #include "node_buffer.h" #include "node_internals.h" +#include "node_process.h" #include "node_url.h" #include "util.h" @@ -244,6 +245,68 @@ TEST_F(EnvironmentTest, LoadEnvironmentWithSource) { .ToLocalChecked()->IsFunction()); } +TEST_F(EnvironmentTest, EmitExperimentalWarning) { + const v8::HandleScope handle_scope(isolate_); + const Argv argv; + Env env{handle_scope, argv}; + + node::LoadEnvironment( + *env, + "globalThis.warningCount = 0;" + "globalThis.throwOnWarning = false;" + "process.emitWarning = function() {" + " globalThis.warningCount++;" + " if (globalThis.throwOnWarning) throw new Error('warning failure');" + "};"); + + static uint64_t test_id = 0; + const std::string warning_prefix = + "cctest experimental warning " + std::to_string(test_id++); + + v8::Maybe first = + node::ProcessEmitExperimentalWarning(*env, warning_prefix + " duplicate"); + ASSERT_TRUE(first.IsJust()); + EXPECT_TRUE(first.FromJust()); + + v8::Maybe duplicate = + node::ProcessEmitExperimentalWarning(*env, warning_prefix + " duplicate"); + ASSERT_TRUE(duplicate.IsJust()); + EXPECT_FALSE(duplicate.FromJust()); + + v8::Local context = env.context(); + v8::Local throw_on_warning_key = + v8::String::NewFromUtf8Literal(isolate_, "throwOnWarning"); + ASSERT_TRUE( + context->Global() + ->Set(context, throw_on_warning_key, v8::Boolean::New(isolate_, true)) + .FromMaybe(false)); + + { + v8::TryCatch try_catch(isolate_); + v8::Maybe failed = node::ProcessEmitExperimentalWarning( + *env, warning_prefix + " retry after exception"); + EXPECT_TRUE(failed.IsNothing()); + EXPECT_TRUE(try_catch.HasCaught()); + } + + ASSERT_TRUE(context->Global() + ->Set(context, + throw_on_warning_key, + v8::Boolean::New(isolate_, false)) + .FromMaybe(false)); + v8::Maybe retry = node::ProcessEmitExperimentalWarning( + *env, warning_prefix + " retry after exception"); + ASSERT_TRUE(retry.IsJust()); + EXPECT_TRUE(retry.FromJust()); + + v8::Local warning_count = + context->Global() + ->Get(context, + v8::String::NewFromUtf8Literal(isolate_, "warningCount")) + .ToLocalChecked(); + EXPECT_EQ(warning_count->Int32Value(context).FromJust(), 3); +} + TEST_F(EnvironmentTest, AtExitWithEnvironment) { const v8::HandleScope handle_scope(isolate_); const Argv argv;