Don't read before the beginning of the string

The code did discard the the data, so it wasn't affecting the comparison
result (tests added anyway), but it could cause crashes if the pointer
to the beginning of the data in the first 8 bytes of a page.

Change-Id: I618e68de329b65de34ef8c934934c3e631cc6c9f
Reported-By: Erik Verbruggen
Reviewed-by: Erik Verbruggen <erik.verbruggen@digia.com>
This commit is contained in:
Thiago Macieira 2014-03-18 16:43:36 -07:00 committed by The Qt Project
parent 8c0919a286
commit 964ac38fb0
2 changed files with 59 additions and 5 deletions

View File

@ -559,11 +559,13 @@ static int ucstrncmp(const QChar *a, const uchar *c, int l)
}
}
// we'll read uc[offset..offset+7] (16 bytes) and c[offset-8..offset+7] (16 bytes)
# ifdef Q_PROCESSOR_X86_64
enum { MaxTailLength = 7 };
// we'll read uc[offset..offset+7] (16 bytes) and c[offset..offset+7] (8 bytes)
if (uc + offset + 7 < e) {
// same, but we'll throw away half the data
__m128i chunk = _mm_loadu_si128((__m128i*)(c + offset - 8));
__m128i secondHalf = _mm_unpackhi_epi8(chunk, nullmask);
// same, but we're using an 8-byte load
__m128i chunk = _mm_cvtsi64_si128(*(long long *)(c + offset));
__m128i secondHalf = _mm_unpacklo_epi8(chunk, nullmask);
__m128i ucdata = _mm_loadu_si128((__m128i*)(uc + offset));
__m128i result = _mm_cmpeq_epi16(secondHalf, ucdata);
@ -577,6 +579,10 @@ static int ucstrncmp(const QChar *a, const uchar *c, int l)
// still matched
offset += 8;
}
# else
// 32-bit, we can't do MOVQ to load 8 bytes
enum { MaxTailLength = 15 };
# endif
// reset uc and c
uc += offset;
@ -584,7 +590,7 @@ static int ucstrncmp(const QChar *a, const uchar *c, int l)
# ifdef Q_COMPILER_LAMBDA
const auto &lambda = [=](int i) { return uc[i] - ushort(c[i]); };
return UnrollTailLoop<7>::exec(e - uc, 0, lambda, lambda);
return UnrollTailLoop<MaxTailLength>::exec(e - uc, 0, lambda, lambda);
# endif
#endif

View File

@ -68,6 +68,8 @@ private slots:
void isEmpty();
void compare_data();
void compare();
void compare2_data();
void compare2();
void operator_eqeq_nullstring();
void toNum();
void toDouble_data();
@ -792,11 +794,17 @@ void tst_QStringRef::compare_data()
QTest::newRow("data3") << QString("abc") << QString("abc") << 0 << 0;
QTest::newRow("data4") << QString("abC") << QString("abc") << -1 << 0;
QTest::newRow("data5") << QString("abc") << QString("abC") << 1 << 0;
QTest::newRow("data10") << QString("abcdefgh") << QString("abcdefgh") << 0 << 0;
QTest::newRow("data11") << QString("abcdefgh") << QString("abCdefgh") << 1 << 0;
QTest::newRow("data12") << QString("0123456789012345") << QString("0123456789012345") << 0 << 0;
QTest::newRow("data13") << QString("0123556789012345") << QString("0123456789012345") << 1 << 1;
// different length
QTest::newRow("data6") << QString("abcdef") << QString("abc") << 1 << 1;
QTest::newRow("data7") << QString("abCdef") << QString("abc") << -1 << 1;
QTest::newRow("data8") << QString("abc") << QString("abcdef") << -1 << -1;
QTest::newRow("data14") << QString("abcdefgh") << QString("abcdefghi") << -1 << -1;
QTest::newRow("data15") << QString("01234567890123456") << QString("0123456789012345") << 1 << 1;
QString upper;
upper += QChar(QChar::highSurrogate(0x10400));
@ -862,6 +870,46 @@ void tst_QStringRef::compare()
}
}
void tst_QStringRef::compare2_data()
{
compare_data();
}
void tst_QStringRef::compare2()
{
QFETCH(QString, s1);
QFETCH(QString, s2);
QFETCH(int, csr);
QFETCH(int, cir);
// prepend and append data
// we only use Latin1 here so isLatin1 still results true
s1.prepend("xyz").append("zyx");
s2.prepend("foobar").append("raboof");
QStringRef r1(&s1, 3, s1.length() - 6);
QStringRef r2(&s2, 6, s2.length() - 12);
QCOMPARE(sign(QStringRef::compare(r1, r2)), csr);
QCOMPARE(sign(r1.compare(r2)), csr);
QCOMPARE(sign(r1.compare(r2, Qt::CaseSensitive)), csr);
QCOMPARE(sign(r1.compare(r2, Qt::CaseInsensitive)), cir);
QCOMPARE(sign(QStringRef::compare(r1, r2, Qt::CaseSensitive)), csr);
QCOMPARE(sign(QStringRef::compare(r1, r2, Qt::CaseInsensitive)), cir);
if (isLatin(s2)) {
QCOMPARE(sign(QStringRef::compare(r1, QLatin1String(r2.toLatin1()))), csr);
QCOMPARE(sign(QStringRef::compare(r1, QLatin1String(r2.toLatin1()), Qt::CaseInsensitive)), cir);
}
if (isLatin(s1)) {
QCOMPARE(sign(QStringRef::compare(r2, QLatin1String(r1.toLatin1()))), -csr);
QCOMPARE(sign(QStringRef::compare(r2, QLatin1String(r1.toLatin1()), Qt::CaseInsensitive)), -cir);
}
}
void tst_QStringRef::toNum()
{
#define TEST_TO_INT(num, func, type) \