From f54d353e3a890207beabd7cced74ce90fb251339 Mon Sep 17 00:00:00 2001 From: Ramya-9353 Date: Sun, 19 Jul 2026 14:01:40 +0000 Subject: [PATCH] fix overlapping memcpy in string::assign(char const*, size_type) When the source pointer aliases the string's own buffer, char_traits::copy (memcpy) is called on overlapping regions, which is undefined behaviour. Detect aliasing with ptr_in_range and use char_traits::move (memmove) followed by term() instead of delegating to impl_.assign, which would write a null terminator that corrupts the source before the copy. --- include/boost/json/impl/string.ipp | 15 ++++++++++++--- test/string.cpp | 30 ++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/include/boost/json/impl/string.ipp b/include/boost/json/impl/string.ipp index afc10ba6f..88217a210 100644 --- a/include/boost/json/impl/string.ipp +++ b/include/boost/json/impl/string.ipp @@ -176,9 +176,18 @@ assign( char const* s, size_type count) { - std::char_traits::copy( - impl_.assign(count, sp_), - s, count); + auto const p = impl_.data(); + if(detail::ptr_in_range(p, p + impl_.size(), s)) + { + std::char_traits::move(p, s, count); + impl_.term(count); + } + else + { + std::char_traits::copy( + impl_.assign(count, sp_), + s, count); + } return *this; } diff --git a/test/string.cpp b/test/string.cpp index 282cad7f4..bb8251396 100644 --- a/test/string.cpp +++ b/test/string.cpp @@ -840,6 +840,36 @@ class string_test }); }; + // assign(char const*, size_type) self-referencing + { + // non-SBO: assign from a substring of itself + { + string s("abcdefghijklmnopqrstuvwxyz0123456789"); + string_view sub(s.data() + 3, s.size() - 3); + std::string expected(sub.data(), sub.size()); + s.assign(sub); + BOOST_TEST(s == expected); + } + + // non-SBO: assign from beginning (prefix) + { + string s("abcdefghijklmnopqrstuvwxyz0123456789"); + string_view sub(s.data(), 10); + std::string expected(sub.data(), sub.size()); + s.assign(sub); + BOOST_TEST(s == expected); + } + + // non-SBO: self-assign via string_view + { + string s("abcdefghijklmnopqrstuvwxyz0123456789"); + string_view sub(s.data(), s.size()); + std::string expected(sub.data(), sub.size()); + s.assign(sub); + BOOST_TEST(s == expected); + } + } + // assign(char const* s) { fail_loop([&](storage_ptr const& sp)