From 1fc0dd09ef6d2f6559287404b0ca3444310e421c Mon Sep 17 00:00:00 2001 From: Mingxin Wang Date: Mon, 7 Sep 2026 16:48:08 -0400 Subject: [PATCH] Refuse a mutable proxy_cast on a const contained value proxy_cast_dispatch guarded a reference result with std::is_const_v, where T is the deduced operand type and is therefore always a reference. A reference type is never const, so the guard never fired and a caller could ask a const proxy for a mutable reference to what it contains and get one, silently casting the constness away. The guard now tests the referenced type. proxy_cast on a proxy whose contained value is const throws bad_proxy_cast, and the pointer form returns nullptr, which is what the const-qualified overload already promised. Reaching a const contained value still works by asking for it as const. --- include/proxy/v4/detail/skills.h | 3 ++- tests/proxy_rtti_tests.cpp | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/include/proxy/v4/detail/skills.h b/include/proxy/v4/detail/skills.h index adee8553..0c64e581 100644 --- a/include/proxy/v4/detail/skills.h +++ b/include/proxy/v4/detail/skills.h @@ -205,7 +205,8 @@ struct proxy_cast_dispatch { if (typeid(T) == *ctx.type_ptr) [[likely]] { if (ctx.is_ref) { if constexpr (std::is_lvalue_reference_v) { - if (ctx.is_const || !std::is_const_v) [[likely]] { + if (ctx.is_const || !std::is_const_v>) + [[likely]] { *static_cast(ctx.result_ptr) = (void*)std::addressof(self); } } diff --git a/tests/proxy_rtti_tests.cpp b/tests/proxy_rtti_tests.cpp index fbfbb95d..91d5da70 100644 --- a/tests/proxy_rtti_tests.cpp +++ b/tests/proxy_rtti_tests.cpp @@ -131,6 +131,26 @@ TEST(ProxyRttiTests, TestIndirectCast_ConstPtr_Fail) { ASSERT_EQ(v, 123); } +TEST(ProxyRttiTests, TestIndirectCast_Ref_ConstTarget) { + const auto p = pro::make_proxy(123); + bool exception_thrown = false; + try { + proxy_cast(*p); + } catch (const pro::bad_proxy_cast&) { + exception_thrown = true; + } + ASSERT_TRUE(exception_thrown); + ASSERT_EQ(proxy_cast(*p), 123); +} + +TEST(ProxyRttiTests, TestIndirectCast_Ptr_ConstTarget) { + const auto p = pro::make_proxy(123); + ASSERT_EQ(proxy_cast(&*p), nullptr); + auto ptr = proxy_cast(&*p); + static_assert(std::is_same_v); + ASSERT_EQ(*ptr, 123); +} + TEST(ProxyRttiTests, TestIndirectTypeid) { int a = 123; pro::proxy p = &a;