ucstrncmp: Fix UBSan report of array overflowing

The expression "a + offset + N" will eventually calculate an address
past the end of a, since we are comparing to end. That's undefined
behavior. Instead, calculate end - a and compare that to offset + N.

This commit subtracts "a" from both sides of the inequalities and swaps
the two sides to make them obey Qt coding style. Testing with GCC 9
(which is the only one I care about) shows the compiler generates the
same code.

Fixes: QTBUG-81218
Change-Id: Id84da383373844f3a4b0fffd15e7c1ab904daccd
Reviewed-by: Olivier Goffart (Woboq GmbH) <ogoffart@woboq.com>
bb10
Thiago Macieira 2020-01-07 16:25:37 -08:00
parent c61cedcc54
commit 64359ad710
1 changed files with 4 additions and 4 deletions

View File

@ -915,7 +915,7 @@ static int ucstrncmp(const QChar *a, const QChar *b, size_t l)
};
// we're going to read a[0..15] and b[0..15] (32 bytes)
for ( ; a + offset + 16 <= end; offset += 16) {
for ( ; end - a >= offset + 16; offset += 16) {
#ifdef __AVX2__
__m256i a_data = _mm256_loadu_si256(reinterpret_cast<const __m256i *>(a + offset));
__m256i b_data = _mm256_loadu_si256(reinterpret_cast<const __m256i *>(b + offset));
@ -939,7 +939,7 @@ static int ucstrncmp(const QChar *a, const QChar *b, size_t l)
}
// we're going to read a[0..7] and b[0..7] (16 bytes)
if (a + offset + 8 <= end) {
if (end - a >= offset + 8) {
__m128i a_data = _mm_loadu_si128(reinterpret_cast<const __m128i *>(a + offset));
__m128i b_data = _mm_loadu_si128(reinterpret_cast<const __m128i *>(b + offset));
if (isDifferent(a_data, b_data))
@ -949,7 +949,7 @@ static int ucstrncmp(const QChar *a, const QChar *b, size_t l)
}
// we're going to read a[0..3] and b[0..3] (8 bytes)
if (a + offset + 4 <= end) {
if (end - a >= offset + 4) {
__m128i a_data = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(a + offset));
__m128i b_data = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(b + offset));
if (isDifferent(a_data, b_data))
@ -970,7 +970,7 @@ static int ucstrncmp(const QChar *a, const QChar *b, size_t l)
if (l >= 8) {
const QChar *end = a + l;
const uint16x8_t mask = { 1, 1 << 1, 1 << 2, 1 << 3, 1 << 4, 1 << 5, 1 << 6, 1 << 7 };
while (a + 7 < end) {
while (end - a > 7) {
uint16x8_t da = vld1q_u16(reinterpret_cast<const uint16_t *>(a));
uint16x8_t db = vld1q_u16(reinterpret_cast<const uint16_t *>(b));