From e4cbf87770199f0337ac3b5d6e0ad23380c07847 Mon Sep 17 00:00:00 2001 From: Ramya Eliger Date: Mon, 6 Jul 2026 15:20:59 +0530 Subject: [PATCH] clamp count in string_impl::replace_unchecked --- .../boost/json/detail/impl/string_impl.ipp | 1 + test/string.cpp | 28 +++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/include/boost/json/detail/impl/string_impl.ipp b/include/boost/json/detail/impl/string_impl.ipp index d6d5a984f..da65c4515 100644 --- a/include/boost/json/detail/impl/string_impl.ipp +++ b/include/boost/json/detail/impl/string_impl.ipp @@ -395,6 +395,7 @@ replace_unchecked( detail::throw_system_error( error::out_of_range, &loc ); } const auto curr_data = data(); + n1 = (std::min)(n1, curr_size - pos); const auto delta = (std::max)(n1, n2) - (std::min)(n1, n2); // if the size doesn't change, we don't need to diff --git a/test/string.cpp b/test/string.cpp index 5a6115b17..5a28b80a6 100644 --- a/test/string.cpp +++ b/test/string.cpp @@ -2419,6 +2419,34 @@ class string_test s1.replace(0, 1, 1, 'a')); }); + // count exceeds size() - pos: clamped to size() - pos (sbo) + fail_loop([&](storage_ptr const& sp) + { + std::string s1(t.v1.data(), t.v1.size()); + string s2(t.v1, sp); + BOOST_TEST(s2.replace(1, s2.size() + 100, 3, 'a') == + s1.replace(1, s1.size() + 100, 3, 'a')); + }); + + // count exceeds size() - pos: erase from pos to end + fail_loop([&](storage_ptr const& sp) + { + std::string s1(t.v2.data(), t.v2.size()); + string s2(t.v2, sp); + BOOST_TEST(s2.replace(0, s2.size() + 100, 0, 'a') == + s1.replace(0, s1.size() + 100, 0, 'a')); + }); + + // count exceeds size() - pos, with growth and realloc + fail_loop([&](storage_ptr const& sp) + { + std::string s1(t.v2.data(), t.v2.size()); + string s2(t.v2, sp); + const auto grow = (std::max)(s1.capacity(), s2.capacity()) + 1; + BOOST_TEST(s2.replace(2, s2.size() + 100, grow, 'a') == + s1.replace(2, s1.size() + 100, grow, 'a')); + }); + // pos out of range fail_loop([&](storage_ptr const& sp) {