diff --git a/src/lib_json/json_value.cpp b/src/lib_json/json_value.cpp index 5823bd1d9..15d4823d9 100644 --- a/src/lib_json/json_value.cpp +++ b/src/lib_json/json_value.cpp @@ -317,8 +317,11 @@ void Value::CZString::swap(CZString& other) { } Value::CZString& Value::CZString::operator=(const CZString& other) { - cstr_ = other.cstr_; - index_ = other.index_; + // Copy-and-swap so a duplicate-policy buffer is deep-copied and the old one + // released once. The prior shallow copy aliased other.cstr_, double-freeing + // an owned string and leaking the overwritten one. + CZString temp(other); + swap(temp); return *this; } diff --git a/src/test_lib_json/main.cpp b/src/test_lib_json/main.cpp index 0d1c33064..244490ef5 100644 --- a/src/test_lib_json/main.cpp +++ b/src/test_lib_json/main.cpp @@ -208,6 +208,19 @@ void ValueTest::runCZStringTests() { // This verifies we don't leak "other" (if fixed) and correctly take "param" str5 = std::move(str3); JSONTEST_ASSERT_STRING_EQUAL(str5.data(), "param"); + + // 7. Copy Assignment (String) + // Copy-assign one owning string over another. The source must remain valid + // (deep copy) and the destination's old buffer must be released once, with no + // double free of the shared buffer at scope exit. + Json::Value::CZString str6("alpha", 5, + Json::Value::CZString::duplicateOnCopy); + Json::Value::CZString str7((str6)); // owning "alpha" + Json::Value::CZString str8("beta", 4, Json::Value::CZString::duplicateOnCopy); + Json::Value::CZString str9((str8)); // owning "beta" + str9 = str7; + JSONTEST_ASSERT_STRING_EQUAL(str9.data(), "alpha"); + JSONTEST_ASSERT_STRING_EQUAL(str7.data(), "alpha"); } JSONTEST_FIXTURE_LOCAL(ValueTest, CZStringCoverage) { runCZStringTests(); }