QByteArray: fix lastIndexOf for char values with set sign bit

lastIndexOf will convert the `needle` to unsigned char, which is then
'upcast' to int, before we search. But the string itself was searched
using signed char, meaning any values with the signed bit set would
mismatch.

Add tests for indexOf and lastIndexOf.

Amends 4c12ae7e67abc3d9b5847f6b61177ede3ee3203b

Fixes: QTBUG-128199
Change-Id: I0ce7d7d9741f21650ef6f0f012a94e00d84a0f02
Reviewed-by: Ahmad Samir <a.samirh78@gmail.com>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
(cherry picked from commit 7b1f3bdc503ea7aceacc9fa8d388d843f1d7b131)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Mårten Nordheim 2024-08-19 14:16:38 +02:00 committed by Qt Cherry-pick Bot
parent 833c0040cb
commit 5caa31cb21
2 changed files with 95 additions and 3 deletions

View File

@ -74,10 +74,10 @@ const void *qmemrchr(const void *s, int needle, size_t size) noexcept
#if QT_CONFIG(memrchr)
return memrchr(s, needle, size);
#endif
auto b = static_cast<const char *>(s);
const char *n = b + size;
auto b = static_cast<const uchar *>(s);
const uchar *n = b + size;
while (n-- != b) {
if (*n == needle)
if (*n == uchar(needle))
return n;
}
return nullptr;

View File

@ -119,6 +119,11 @@ private slots:
void isUpper();
void isLower();
void indexOf_data();
void indexOf();
void lastIndexOf_data();
void lastIndexOf();
void macTypes();
void stdString();
@ -2588,6 +2593,93 @@ void tst_QByteArray::isLower()
QVERIFY(QByteArray("`abyz{").isLower());
}
using ByteArrayOrChar = std::variant<QByteArray, char>;
void tst_QByteArray::indexOf_data()
{
qRegisterMetaType<ByteArrayOrChar>();
QTest::addColumn<QByteArray>("haystack");
QTest::addColumn<ByteArrayOrChar>("needle");
QTest::addColumn<int>("expectedIndex");
QTest::addColumn<int>("from");
const QByteArray haystack = "abc 123 cba \x80 \x08 \x00 \x01 \x81"_ba;
QTest::newRow("not_found_1_char_string") << haystack << ByteArrayOrChar("d"_ba) << -1 << 0;
QTest::newRow("not_found_char") << haystack << ByteArrayOrChar('d') << -1 << 0;
QTest::newRow("not_found_string") << haystack << ByteArrayOrChar("abcd"_ba) << -1 << 0;
QTest::newRow("found_1_char_string") << haystack << ByteArrayOrChar("a"_ba) << 0 << 0;
QTest::newRow("found_char") << haystack << ByteArrayOrChar('a') << 0 << 0;
QTest::newRow("found_string") << haystack << ByteArrayOrChar("cba"_ba) << 8 << 0;
QTest::newRow("found_empty_string") << haystack << ByteArrayOrChar(""_ba) << 0 << 0;
QTest::newRow("found_embedded_null") << haystack << ByteArrayOrChar("\x00"_ba) << 16 << 0;
QTest::newRow("not_found_terminating_null") << haystack << ByteArrayOrChar("\x00"_ba) << -1 << 17;
QTest::newRow("found_char_star_0x80") << haystack << ByteArrayOrChar("\x80"_ba) << 12 << 0;
QTest::newRow("found_char_0x80") << haystack << ByteArrayOrChar('\x80') << 12 << 0;
QTest::newRow("found_char_0x81") << haystack << ByteArrayOrChar('\x81') << 20 << 0;
}
void tst_QByteArray::indexOf()
{
QFETCH(QByteArray, haystack);
QFETCH(ByteArrayOrChar, needle);
QFETCH(int, expectedIndex);
QFETCH(int, from);
if (auto *qba = std::get_if<QByteArray>(&needle)) {
QCOMPARE(haystack.indexOf(*qba, from), expectedIndex);
} else {
char c = std::get<char>(needle);
QCOMPARE(haystack.indexOf(c, from), expectedIndex);
}
}
void tst_QByteArray::lastIndexOf_data()
{
qRegisterMetaType<ByteArrayOrChar>();
QTest::addColumn<QByteArray>("haystack");
QTest::addColumn<ByteArrayOrChar>("needle");
QTest::addColumn<int>("expectedIndex");
QTest::addColumn<int>("from");
const QByteArray haystack = "abc 123 cba \x80 \x08 \x00 \x01 \x81"_ba;
QTest::newRow("not_found_1_char_string") << haystack << ByteArrayOrChar("d"_ba) << -1 << -1;
QTest::newRow("not_found_char") << haystack << ByteArrayOrChar('d') << -1 << -1;
QTest::newRow("not_found_string") << haystack << ByteArrayOrChar("abcd"_ba) << -1 << -1;
QTest::newRow("found_1_char_string") << haystack << ByteArrayOrChar("a"_ba) << 10 << -1;
QTest::newRow("found_char") << haystack << ByteArrayOrChar('a') << 10 << -1;
QTest::newRow("found_string") << haystack << ByteArrayOrChar("cba"_ba) << 8 << -1;
QTest::newRow("found_empty_string") << haystack << ByteArrayOrChar(""_ba) << haystack.size() << -1;
QTest::newRow("found_embedded_null") << haystack << ByteArrayOrChar("\x00"_ba) << 16 << -1;
QTest::newRow("not_found_leading_null") << haystack << ByteArrayOrChar("\x00"_ba) << -1 << 15;
QTest::newRow("found_char_star_0x80") << haystack << ByteArrayOrChar("\x80"_ba) << 12 << -1;
QTest::newRow("found_char_0x80") << haystack << ByteArrayOrChar('\x80') << 12 << -1;
QTest::newRow("found_char_0x81") << haystack << ByteArrayOrChar('\x81') << 20 << -1;
}
void tst_QByteArray::lastIndexOf()
{
QFETCH(QByteArray, haystack);
QFETCH(ByteArrayOrChar, needle);
QFETCH(int, expectedIndex);
QFETCH(int, from);
if (auto *qba = std::get_if<QByteArray>(&needle)) {
QCOMPARE(haystack.lastIndexOf(*qba, from), expectedIndex);
} else {
char c = std::get<char>(needle);
QCOMPARE(haystack.lastIndexOf(c, from), expectedIndex);
}
}
void tst_QByteArray::macTypes()
{
#ifndef Q_OS_DARWIN