Merge to XFA: Fix potential UAF in ConcatInPlace.

Original Review URL: https://codereview.chromium.org/1130763007
TBR=thestig@chromium.org

Review URL: https://codereview.chromium.org/1123333004
diff --git a/core/src/fxcrt/fx_basic_bstring.cpp b/core/src/fxcrt/fx_basic_bstring.cpp
index 87e50e7..781b821 100644
--- a/core/src/fxcrt/fx_basic_bstring.cpp
+++ b/core/src/fxcrt/fx_basic_bstring.cpp
@@ -422,9 +422,7 @@
         return;
     }
     if (m_pData->m_nRefs > 1 || m_pData->m_nDataLength + nSrcLen > m_pData->m_nAllocLength) {
-        StringData* pOldData = m_pData;
         ConcatCopy(m_pData->m_nDataLength, m_pData->m_String, nSrcLen, lpszSrcData);
-        pOldData->Release();
     } else {
         FXSYS_memcpy32(m_pData->m_String + m_pData->m_nDataLength, lpszSrcData, nSrcLen);
         m_pData->m_nDataLength += nSrcLen;
@@ -435,14 +433,17 @@
                                 FX_STRSIZE nSrc2Len, FX_LPCSTR lpszSrc2Data)
 {
     int nNewLen = nSrc1Len + nSrc2Len;
-    if (nNewLen == 0) {
+    if (nNewLen <= 0) {
         return;
     }
+    // Don't release until done copying, might be one of the arguments.
+    StringData* pOldData = m_pData;
     m_pData = StringData::Create(nNewLen);
     if (m_pData) {
-        FXSYS_memcpy32(m_pData->m_String, lpszSrc1Data, nSrc1Len);
-        FXSYS_memcpy32(m_pData->m_String + nSrc1Len, lpszSrc2Data, nSrc2Len);
+        memcpy(m_pData->m_String, lpszSrc1Data, nSrc1Len);
+        memcpy(m_pData->m_String + nSrc1Len, lpszSrc2Data, nSrc2Len);
     }
+    pOldData->Release();
 }
 CFX_ByteString CFX_ByteString::Mid(FX_STRSIZE nFirst) const
 {
diff --git a/core/src/fxcrt/fx_basic_bstring_unittest.cpp b/core/src/fxcrt/fx_basic_bstring_unittest.cpp
index 1f80207..bcdd33b 100644
--- a/core/src/fxcrt/fx_basic_bstring_unittest.cpp
+++ b/core/src/fxcrt/fx_basic_bstring_unittest.cpp
@@ -288,6 +288,33 @@
   EXPECT_NE(null_string, non_null_string);
 }
 
+TEST(fxcrt, ByteStringConcatInPlace) {
+    CFX_ByteString fred;
+    fred.ConcatInPlace(4, "FRED");
+    EXPECT_EQ("FRED", fred);
+
+    fred.ConcatInPlace(2, "DY");
+    EXPECT_EQ("FREDDY", fred);
+
+    fred.Delete(3, 3);
+    EXPECT_EQ("FRE", fred);
+
+    fred.ConcatInPlace(1, "D");
+    EXPECT_EQ("FRED", fred);
+
+    CFX_ByteString copy = fred;
+    fred.ConcatInPlace(2, "DY");
+    EXPECT_EQ("FREDDY", fred);
+    EXPECT_EQ("FRED", copy);
+
+    // Test invalid arguments.
+    copy = fred;
+    fred.ConcatInPlace(-6, "freddy");
+    CFX_ByteString not_aliased("xxxxxx");
+    EXPECT_EQ("FREDDY", fred);
+    EXPECT_EQ("xxxxxx", not_aliased);
+}
+
 TEST(fxcrt, ByteStringCNotNull) {
   CFX_ByteStringC string3("abc");
   CFX_ByteStringC string6("abcdef");
diff --git a/core/src/fxcrt/fx_basic_wstring.cpp b/core/src/fxcrt/fx_basic_wstring.cpp
index da02205..3c54ca9 100644
--- a/core/src/fxcrt/fx_basic_wstring.cpp
+++ b/core/src/fxcrt/fx_basic_wstring.cpp
@@ -237,9 +237,7 @@
         return;
     }
     if (m_pData->m_nRefs > 1 || m_pData->m_nDataLength + nSrcLen > m_pData->m_nAllocLength) {
-        StringData* pOldData = m_pData;
         ConcatCopy(m_pData->m_nDataLength, m_pData->m_String, nSrcLen, lpszSrcData);
-        pOldData->Release();
     } else {
         FXSYS_memcpy32(m_pData->m_String + m_pData->m_nDataLength, lpszSrcData, nSrcLen * sizeof(FX_WCHAR));
         m_pData->m_nDataLength += nSrcLen;
@@ -250,14 +248,17 @@
                                 FX_STRSIZE nSrc2Len, FX_LPCWSTR lpszSrc2Data)
 {
     FX_STRSIZE nNewLen = nSrc1Len + nSrc2Len;
-    if (nNewLen == 0) {
+    if (nNewLen <= 0) {
         return;
     }
+    // Don't release until done copying, might be one of the arguments.
+    StringData* pOldData = m_pData;
     m_pData = StringData::Create(nNewLen);
     if (m_pData) {
-        FXSYS_memcpy32(m_pData->m_String, lpszSrc1Data, nSrc1Len * sizeof(FX_WCHAR));
-        FXSYS_memcpy32(m_pData->m_String + nSrc1Len, lpszSrc2Data, nSrc2Len * sizeof(FX_WCHAR));
+        wmemcpy(m_pData->m_String, lpszSrc1Data, nSrc1Len);
+        wmemcpy(m_pData->m_String + nSrc1Len, lpszSrc2Data, nSrc2Len);
     }
+    pOldData->Release();
 }
 void CFX_WideString::CopyBeforeWrite()
 {
diff --git a/core/src/fxcrt/fx_basic_wstring_unittest.cpp b/core/src/fxcrt/fx_basic_wstring_unittest.cpp
index 21b5ae5..847e5e8 100644
--- a/core/src/fxcrt/fx_basic_wstring_unittest.cpp
+++ b/core/src/fxcrt/fx_basic_wstring_unittest.cpp
@@ -249,6 +249,33 @@
     EXPECT_TRUE(c_string3 != wide_string);
 }
 
+TEST(fxcrt, WideStringConcatInPlace) {
+    CFX_WideString fred;
+    fred.ConcatInPlace(4, L"FRED");
+    EXPECT_EQ(L"FRED", fred);
+
+    fred.ConcatInPlace(2, L"DY");
+    EXPECT_EQ(L"FREDDY", fred);
+
+    fred.Delete(3, 3);
+    EXPECT_EQ(L"FRE", fred);
+
+    fred.ConcatInPlace(1, L"D");
+    EXPECT_EQ(L"FRED", fred);
+
+    CFX_WideString copy = fred;
+    fred.ConcatInPlace(2, L"DY");
+    EXPECT_EQ(L"FREDDY", fred);
+    EXPECT_EQ(L"FRED", copy);
+
+    // Test invalid arguments.
+    copy = fred;
+    fred.ConcatInPlace(-6, L"freddy");
+    CFX_WideString not_aliased(L"xxxxxx");
+    EXPECT_EQ(L"FREDDY", fred);
+    EXPECT_EQ(L"xxxxxx", not_aliased);
+}
+
 #define ByteStringLiteral(str) CFX_ByteString(FX_BSTRC(str))
 
 TEST(fxcrt, WideStringUTF16LE_Encode) {