fixing overrelease and out-of-bounds write, fixes #13725
[wxWidgets.git] / src / common / stringimpl.cpp
index 4c309175217b9b329002b98b6a11ba0979b91230..498793722e8f171a109b642db979fbcc0ff57ec6 100644 (file)
@@ -77,9 +77,9 @@ const size_t wxStringImpl::npos = (size_t) -1;
 
 // FIXME-UTF8: get rid of this, have only one wxEmptyString
 #if wxUSE_UNICODE_UTF8
-extern const wxStringCharType WXDLLIMPEXP_BASE *wxEmptyStringImpl = "";
+const wxStringCharType WXDLLIMPEXP_BASE *wxEmptyStringImpl = "";
 #endif
-extern const wxChar WXDLLIMPEXP_BASE *wxEmptyString = _T("");
+const wxChar WXDLLIMPEXP_BASE *wxEmptyString = wxT("");
 
 #else
 
@@ -95,10 +95,10 @@ static const struct
 // empty C style string: points to 'string data' byte of g_strEmpty
 #if wxUSE_UNICODE_UTF8
 // FIXME-UTF8: get rid of this, have only one wxEmptyString
-extern const wxStringCharType WXDLLIMPEXP_BASE *wxEmptyStringImpl = &g_strEmpty.dummy;
-extern const wxChar WXDLLIMPEXP_BASE *wxEmptyString = _T("");
+const wxStringCharType WXDLLIMPEXP_BASE *wxEmptyStringImpl = &g_strEmpty.dummy;
+const wxChar WXDLLIMPEXP_BASE *wxEmptyString = wxT("");
 #else
-extern const wxStringCharType WXDLLIMPEXP_BASE *wxEmptyString = &g_strEmpty.dummy;
+const wxStringCharType WXDLLIMPEXP_BASE *wxEmptyString = &g_strEmpty.dummy;
 #endif
 
 #endif
@@ -111,19 +111,26 @@ extern const wxStringCharType WXDLLIMPEXP_BASE *wxEmptyString = &g_strEmpty.dumm
 // ----------------------------------------------------------------------------
 
 // this small class is used to gather statistics for performance tuning
+
+// uncomment this to enable gathering of some statistics about wxString
+// efficiency
 //#define WXSTRING_STATISTICS
+
 #ifdef  WXSTRING_STATISTICS
   class Averager
   {
   public:
     Averager(const wxStringCharType *sz) { m_sz = sz; m_nTotal = m_nCount = 0; }
    ~Averager()
-   { wxPrintf("wxString: average %s = %f\n", m_sz, ((float)m_nTotal)/m_nCount); }
+    {
+        wxPrintf("wxString %s: total = %lu, average = %f\n",
+                 m_sz, m_nTotal, ((float)m_nTotal)/m_nCount);
+    }
 
     void Add(size_t n) { m_nTotal += n; m_nCount++; }
 
   private:
-    size_t m_nCount, m_nTotal;
+    unsigned long m_nCount, m_nTotal;
     const wxStringCharType *m_sz;
   } g_averageLength("allocation size"),
     g_averageSummandLength("summand length"),
@@ -159,7 +166,7 @@ void wxStringImpl::InitWith(const wxStringCharType *psz,
 
   // if the length is not given, assume the string to be NUL terminated
   if ( nLength == npos ) {
-    wxASSERT_MSG( nPos <= wxStrlen(psz), _T("index out of bounds") );
+    wxASSERT_MSG( nPos <= wxStrlen(psz), wxT("index out of bounds") );
 
     nLength = wxStrlen(psz + nPos);
   }
@@ -169,7 +176,7 @@ void wxStringImpl::InitWith(const wxStringCharType *psz,
   if ( nLength > 0 ) {
     // trailing '\0' is written in AllocBuffer()
     if ( !AllocBuffer(nLength) ) {
-      wxFAIL_MSG( _T("out of memory in wxStringImpl::InitWith") );
+      wxFAIL_MSG( wxT("out of memory in wxStringImpl::InitWith") );
       return;
     }
     wxStringMemcpy(m_pchData, psz + nPos, nLength);
@@ -180,11 +187,11 @@ wxStringImpl::wxStringImpl(const_iterator first, const_iterator last)
 {
   if ( last >= first )
   {
-    InitWith(first, 0, last - first);
+    InitWith(first.GetPtr(), 0, last - first);
   }
   else
   {
-    wxFAIL_MSG( _T("first must be before last") );
+    wxFAIL_MSG( wxT("first must be before last") );
     Init();
   }
 }
@@ -207,8 +214,8 @@ bool wxStringImpl::AllocBuffer(size_t nLen)
   wxASSERT( nLen >  0 );
 
   // make sure that we don't overflow
-  wxASSERT( nLen < (INT_MAX / sizeof(wxStringCharType)) -
-                   (sizeof(wxStringData) + EXTRA_ALLOC + 1) );
+  wxCHECK( nLen < (INT_MAX / sizeof(wxStringCharType)) -
+                  (sizeof(wxStringData) + EXTRA_ALLOC + 1), false );
 
   STATISTICS_ADD(Length, nLen);
 
@@ -304,7 +311,7 @@ wxStringImpl& wxStringImpl::append(size_t n, wxStringCharType ch)
     size_type len = length();
 
     if ( !Alloc(len + n) || !CopyBeforeWrite() ) {
-      wxFAIL_MSG( _T("out of memory in wxStringImpl::append") );
+      wxFAIL_MSG( wxT("out of memory in wxStringImpl::append") );
       return *this;
     }
     GetStringData()->nDataLength = len + n;
@@ -335,6 +342,8 @@ bool wxStringImpl::Alloc(size_t nLen)
   wxStringData *pData = GetStringData();
   if ( pData->nAllocLength <= nLen ) {
     if ( pData->IsEmpty() ) {
+      STATISTICS_ADD(Length, nLen);
+
       nLen += EXTRA_ALLOC;
 
       pData = (wxStringData *)
@@ -386,14 +395,14 @@ bool wxStringImpl::Alloc(size_t nLen)
 
 wxStringImpl::iterator wxStringImpl::begin()
 {
-    if (length() > 0)
+    if ( !empty() )
         CopyBeforeWrite();
     return m_pchData;
 }
 
 wxStringImpl::iterator wxStringImpl::end()
 {
-    if (length() > 0)
+    if ( !empty() )
         CopyBeforeWrite();
     return m_pchData + length();
 }
@@ -427,7 +436,7 @@ wxStringImpl& wxStringImpl::insert(size_t nPos,
     if ( n == 0 ) return *this;
 
     if ( !Alloc(length() + n) || !CopyBeforeWrite() ) {
-        wxFAIL_MSG( _T("out of memory in wxStringImpl::insert") );
+        wxFAIL_MSG( wxT("out of memory in wxStringImpl::insert") );
         return *this;
     }
 
@@ -519,7 +528,7 @@ size_t wxStringImpl::rfind(const wxStringImpl& str, size_t nStart) const
     if ( length() >= str.length() )
     {
         // avoids a corner case later
-        if ( length() == 0 && str.length() == 0 )
+        if ( empty() && str.empty() )
             return 0;
 
         // "top" is the point where search starts from
@@ -578,7 +587,7 @@ wxStringImpl& wxStringImpl::replace(size_t nStart, size_t nLen,
     const size_t lenOld = length();
 
     wxASSERT_MSG( nStart <= lenOld,
-                  _T("index out of bounds in wxStringImpl::replace") );
+                  wxT("index out of bounds in wxStringImpl::replace") );
     size_t nEnd = nStart + nLen;
     if ( nLen > lenOld - nStart )
     {
@@ -646,7 +655,7 @@ wxStringImpl& wxStringImpl::operator=(wxStringCharType ch)
 {
   wxStringCharType c(ch);
   if ( !AssignCopy(1, &c) ) {
-    wxFAIL_MSG( _T("out of memory in wxStringImpl::operator=(wxStringCharType)") );
+    wxFAIL_MSG( wxT("out of memory in wxStringImpl::operator=(wxStringCharType)") );
   }
   return *this;
 }
@@ -655,7 +664,7 @@ wxStringImpl& wxStringImpl::operator=(wxStringCharType ch)
 wxStringImpl& wxStringImpl::operator=(const wxStringCharType *psz)
 {
   if ( !AssignCopy(wxStrlen(psz), psz) ) {
-    wxFAIL_MSG( _T("out of memory in wxStringImpl::operator=(const wxStringCharType *)") );
+    wxFAIL_MSG( wxT("out of memory in wxStringImpl::operator=(const wxStringCharType *)") );
   }
   return *this;
 }
@@ -672,7 +681,11 @@ bool wxStringImpl::AssignCopy(size_t nSrcLen,
       // allocation failure handled by caller
       return false;
     }
-    memcpy(m_pchData, pszSrcData, nSrcLen*sizeof(wxStringCharType));
+
+    // use memmove() and not memcpy() here as we might be copying from our own
+    // buffer in case of assignment such as "s = s.c_str()" (see #11294)
+    memmove(m_pchData, pszSrcData, nSrcLen*sizeof(wxStringCharType));
+
     GetStringData()->nDataLength = nSrcLen;
     m_pchData[nSrcLen] = wxT('\0');
   }
@@ -775,10 +788,10 @@ void wxStringImpl::DoUngetWriteBuf(size_t nLen)
 {
   wxStringData * const pData = GetStringData();
 
-  wxASSERT_MSG( nLen < pData->nAllocLength, _T("buffer overrun") );
+  wxASSERT_MSG( nLen < pData->nAllocLength, wxT("buffer overrun") );
 
   // the strings we store are always NUL-terminated
-  pData->data()[nLen] = _T('\0');
+  pData->data()[nLen] = wxT('\0');
   pData->nDataLength = nLen;
   pData->Validate(true);
 }