From efc5fa99a24ffa0877063b051787978e34d25cfc Mon Sep 17 00:00:00 2001 From: Archkon <180910180+Archkon@users.noreply.github.com> Date: Fri, 31 Jul 2026 12:06:40 +0800 Subject: [PATCH] src: constrain COW forwarding constructors Exclude the wrapper type from the forwarding constructors so that non-const lvalue copies select the copy constructor. Signed-off-by: Archkon <180910180+Archkon@users.noreply.github.com> --- src/node_threadsafe_cow.h | 10 +++++++++- test/cctest/test_per_process.cc | 22 ++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/node_threadsafe_cow.h b/src/node_threadsafe_cow.h index 8cfdd006b12f..4d823b23f59d 100644 --- a/src/node_threadsafe_cow.h +++ b/src/node_threadsafe_cow.h @@ -6,7 +6,9 @@ #include "util.h" #include "uv.h" -#include // std::shared_ptr +#include +#include // std::shared_ptr +#include #include // std::forward namespace node { @@ -17,6 +19,8 @@ template class CopyOnWrite final { public: template + requires(!(sizeof...(Args) == 1 && + (std::same_as> || ...))) explicit CopyOnWrite(Args&&... args) : data_(std::make_shared(std::forward(args)...)) {} @@ -57,6 +61,10 @@ class ThreadsafeCopyOnWrite final { public: template + requires( + !(sizeof...(Args) == 1 && + (std::same_as> || + ...))) ThreadsafeCopyOnWrite(Args&&... args) : impl_(T(std::forward(args)...)) {} diff --git a/test/cctest/test_per_process.cc b/test/cctest/test_per_process.cc index 7a6f53d56222..dce250e18f8d 100644 --- a/test/cctest/test_per_process.cc +++ b/test/cctest/test_per_process.cc @@ -6,6 +6,8 @@ #include +using node::CopyOnWrite; +using node::ThreadsafeCopyOnWrite; using node::builtins::BuiltinLoader; using node::builtins::BuiltinSourceMap; @@ -18,6 +20,26 @@ class PerProcessTest : public ::testing::Test { namespace { +TEST(CopyOnWriteTest, CopiesFromNonConstLvalue) { + CopyOnWrite original(42); + CopyOnWrite copy(original); + + *copy.write() = 43; + + EXPECT_EQ(*original, 42); + EXPECT_EQ(*copy, 43); +} + +TEST(ThreadsafeCopyOnWriteTest, CopiesFromNonConstLvalue) { + ThreadsafeCopyOnWrite original(42); + ThreadsafeCopyOnWrite copy(original); + + *copy.write() = 43; + + EXPECT_EQ(*original.read(), 42); + EXPECT_EQ(*copy.read(), 43); +} + TEST_F(PerProcessTest, EmbeddedSources) { const auto& sources = PerProcessTest::get_sources_for_test(); ASSERT_TRUE(std::any_of(sources.cbegin(), sources.cend(), [](auto p) {