QString: remove a try/catch from replace_helper()

I think it was there because of of the QChar array allocated on the
heap (to store a copy of the "after" string when it's part of 'this'
string) and the subsequent ::free() call; instead split some code to a
static helper, and store the copy in a QVarLengthArray; the latter has
SSO, so it'll only heap-allocate if needed, and will take care of
deleting the data.

Remove now unused textCopy() method.

Change-Id: Iaf29d19ebd40d24948f0859d80f45e4c16e5bbce
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Reviewed-by: Marc Mutz <marc.mutz@qt.io>
This commit is contained in:
Ahmad Samir 2022-11-20 21:14:14 +02:00
parent 9532339788
commit 3575d2d028

View File

@ -3502,26 +3502,9 @@ QString &QString::remove(QChar ch, Qt::CaseSensitivity cs)
\sa remove() \sa remove()
*/ */
namespace { // helpers for replace and its helper: static void do_replace_helper(QString &str, size_t *indices, qsizetype nIndices, qsizetype blen,
QChar *textCopy(const QChar *start, qsizetype len) const QChar *after, qsizetype alen)
{ {
const size_t size = len * sizeof(QChar);
QChar *const copy = static_cast<QChar *>(::malloc(size));
Q_CHECK_PTR(copy);
::memcpy(copy, start, size);
return copy;
}
} // end namespace
static void replace_helper(QString &str, size_t *indices, qsizetype nIndices, qsizetype blen, const QChar *after, qsizetype alen)
{
// Copy after if it lies inside our own d.b area (which we could
// possibly invalidate via a realloc or modify by replacement).
QChar *afterBuffer = nullptr;
if (QtPrivate::q_points_into_range(after, str)) // Use copy in place of vulnerable original:
after = afterBuffer = textCopy(after, alen);
QT_TRY {
if (blen == alen) { if (blen == alen) {
// replace in place // replace in place
str.detach(); str.detach();
@ -3547,10 +3530,10 @@ static void replace_helper(QString &str, size_t *indices, qsizetype nIndices, qs
} }
movestart = indices[i] + blen; movestart = indices[i] + blen;
} }
qsizetype msize = str.data_ptr()->size - movestart; qsizetype msize = str.data_ptr().size - movestart;
if (msize > 0) if (msize > 0)
memmove(str.data_ptr().data() + to, str.data_ptr().data() + movestart, msize * sizeof(QChar)); memmove(str.data_ptr().data() + to, str.data_ptr().data() + movestart, msize * sizeof(QChar));
str.resize(str.data_ptr()->size - nIndices*(blen-alen)); str.resize(str.data_ptr().size - nIndices*(blen-alen));
} else { } else {
// replace from back // replace from back
qsizetype adjust = nIndices*(alen-blen); qsizetype adjust = nIndices*(alen-blen);
@ -3569,11 +3552,18 @@ static void replace_helper(QString &str, size_t *indices, qsizetype nIndices, qs
moveend = movestart-blen; moveend = movestart-blen;
} }
} }
} QT_CATCH(const std::bad_alloc &) {
::free(afterBuffer);
QT_RETHROW;
} }
::free(afterBuffer);
static void replace_helper(QString &str, size_t *indices, qsizetype nIndices, qsizetype blen, const QChar *after, qsizetype alen)
{
// Copy after if it lies inside our own d.b area (which we could
// possibly invalidate via a realloc or modify by replacement).
if (QtPrivate::q_points_into_range(after, str)) {
const QVarLengthArray<QChar> after_copy{after, after+alen};
do_replace_helper(str, indices, nIndices, blen, after_copy.data(), after_copy.size());
} else {
do_replace_helper(str, indices, nIndices, blen, after, alen);
}
} }
/*! /*!