QString::arg: don't pass nullptr to memcpy()

A null QString / QStringView has a null begin pointer stored as its
array beginning (something we hide a little in the QString::data()
function, but not in QStringView::data()). We've been passing a null
pointer to memcpy() every time someone passed a null QStringView for
QString's single-argument arg() call, though not the multi-string arg()
version (which is the only one QStringView offers).

Commit f5021835dfb4b0bf974794b598cbdf9f0f95898d made this worse by
making QStringViews created from null QStrings retain the nullness (as
was intended).

Fixes: QTBUG-120624
Pick-to: 6.5 6.2
Change-Id: I6e2677aad2ab45759db2fffd17a870639b19340b
Reviewed-by: Marc Mutz <marc.mutz@qt.io>
(cherry picked from commit d351a97e85e5ed8acd7ad1357ef76dc2e0ad639f)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
(cherry picked from commit 923918c66b98457a854b8b1c1c1f3850ec4b9880)
This commit is contained in:
Thiago Macieira 2024-01-08 14:47:12 -03:00 committed by Qt Cherry-pick Bot
parent f0e4f50fd1
commit 59a273d152
3 changed files with 23 additions and 3 deletions

View File

@ -8384,7 +8384,8 @@ static QString replaceArgEscapes(QStringView s, const ArgEscapeData &d, qsizetyp
rc = std::fill_n(rc, pad_chars, fillChar); rc = std::fill_n(rc, pad_chars, fillChar);
} }
memcpy(rc, use.data(), use.size() * sizeof(QChar)); if (use.size())
memcpy(rc, use.data(), use.size() * sizeof(QChar));
rc += use.size(); rc += use.size();
if (field_width < 0) { // right padded if (field_width < 0) { // right padded

View File

@ -6241,9 +6241,18 @@ void tst_QString::arg()
QString s13(u"%1% %x%c%2 %d%2-%"_s); QString s13(u"%1% %x%c%2 %d%2-%"_s);
QString s14(u"%1%2%3"_s); QString s14(u"%1%2%3"_s);
const QString null;
const QString empty(u""_s);
const QString foo(u"foo"_s); const QString foo(u"foo"_s);
const QString bar(u"bar"_s); const QString bar(u"bar"_s);
Q_ASSERT(null.isNull());
Q_ASSERT(!empty.isNull());
QCOMPARE(s4.arg(null), "[]"_L1);
QCOMPARE(s4.arg(empty), "[]"_L1);
QCOMPARE(s4.arg(QStringView()), "[]"_L1);
QCOMPARE(s4.arg(QStringView(u"")), "[]"_L1);
QCOMPARE(s4.arg(foo), "[foo]"_L1); QCOMPARE(s4.arg(foo), "[foo]"_L1);
QCOMPARE( s5.arg(QLatin1String("foo")), QLatin1String("[foo]") ); QCOMPARE( s5.arg(QLatin1String("foo")), QLatin1String("[foo]") );
QCOMPARE( s6.arg(u"foo"), QLatin1String("[foo]") ); QCOMPARE( s6.arg(u"foo"), QLatin1String("[foo]") );
@ -6336,6 +6345,14 @@ void tst_QString::arg()
QCOMPARE(QString(u"%%%"_s).arg(0), "%%%"_L1); QCOMPARE(QString(u"%%%"_s).arg(0), "%%%"_L1);
QCOMPARE(QString(u"%%%1%%%2"_s).arg(foo).arg(bar), "%%foo%%bar"_L1); QCOMPARE(QString(u"%%%1%%%2"_s).arg(foo).arg(bar), "%%foo%%bar"_L1);
QCOMPARE(u"%1"_s.arg(null, 3), " "_L1);
QCOMPARE(u"%1"_s.arg(empty, 3), " "_L1);
QCOMPARE(u"%1"_s.arg(QStringView(), 3), " "_L1);
QCOMPARE(u"%1"_s.arg(QStringView(u""), 3), " "_L1);
QCOMPARE(u"%1%1"_s.arg(null), ""_L1);
QCOMPARE(u"%2%1"_s.arg(empty), "%2"_L1);
QCOMPARE(u"%2%1"_s.arg(QStringView()), "%2"_L1);
QCOMPARE(u"%2%1"_s.arg(QStringView(u"")), "%2"_L1);
QCOMPARE(u"%1"_s.arg(u"hello"_s, -10), "hello "_L1); QCOMPARE(u"%1"_s.arg(u"hello"_s, -10), "hello "_L1);
QCOMPARE(u"%1"_s.arg("hello"_L1, -5), "hello"_L1); QCOMPARE(u"%1"_s.arg("hello"_L1, -5), "hello"_L1);
QCOMPARE(u"%1"_s.arg(u"hello", -2), "hello"_L1); QCOMPARE(u"%1"_s.arg(u"hello", -2), "hello"_L1);
@ -6345,8 +6362,6 @@ void tst_QString::arg()
QCOMPARE(u"%1"_s.arg(u"hello"_s, 10), " hello"_L1); QCOMPARE(u"%1"_s.arg(u"hello"_s, 10), " hello"_L1);
QCOMPARE(u"%1%1"_s.arg(u"hello"_s), "hellohello"_L1); QCOMPARE(u"%1%1"_s.arg(u"hello"_s), "hellohello"_L1);
QCOMPARE(u"%2%1"_s.arg(u"hello"_s), "%2hello"_L1); QCOMPARE(u"%2%1"_s.arg(u"hello"_s), "%2hello"_L1);
QCOMPARE(u"%1%1"_s.arg(QString()), QLatin1String(""));
QCOMPARE(u"%2%1"_s.arg(u""_s), "%2"_L1);
QCOMPARE( QString(u"%2 %L1"_s).arg(12345.6789).arg(12345.6789), QCOMPARE( QString(u"%2 %L1"_s).arg(12345.6789).arg(12345.6789),
QLatin1String("12345.7 12.345,7") ); QLatin1String("12345.7 12.345,7") );

View File

@ -467,6 +467,10 @@ void tst_QStringView::at() const
void tst_QStringView::arg() const void tst_QStringView::arg() const
{ {
// nullness checks
QCOMPARE(QStringView().arg(QStringView()), "");
QCOMPARE(QStringView("%1").arg(QStringView()), "");
#define CHECK1(pattern, arg1, expected) \ #define CHECK1(pattern, arg1, expected) \
do { \ do { \
auto p = QStringView(u"" pattern); \ auto p = QStringView(u"" pattern); \