QBitArray: fix GCC 13 warnings by improving code

GCC 13 has been complaining that QBitArray could be accessing past the
end of an array (specifically, the 1-element array QByteArray::_empty).
That's caused by the 'QByteArray::data() const' being:

 #if QT5_NULL_STRINGS == 1
     return d.data() ? d.data() : &_empty;
 #else
     return d.data();
 #endif

A way to avoid this is to use operator[], which doesn't attempt to hide
null pointers (it has an assertion).

This is accomplished by writing nicer, more readable code, which is a
nice benefit.

Fixes: QTBUG-118631
Change-Id: I85b3fc2dd45c4693be13fffd179579615a6ac98d
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
(cherry picked from commit 8739963c8147269bc64b74c2c513cc8da4ce738b)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Thiago Macieira 2023-11-07 14:58:13 -08:00 committed by Qt Cherry-pick Bot
parent 7f7fd8ce96
commit f003d43eb0

View File

@ -18,6 +18,18 @@ class Q_CORE_EXPORT QBitArray
friend Q_CORE_EXPORT size_t qHash(const QBitArray &key, size_t seed) noexcept; friend Q_CORE_EXPORT size_t qHash(const QBitArray &key, size_t seed) noexcept;
QByteArray d; QByteArray d;
template <typename BitArray> static auto bitLocation(BitArray &ba, qsizetype i)
{
Q_ASSERT(size_t(i) < size_t(ba.size()));
struct R {
decltype(ba.d[1]) byte;
uchar bitMask;
};
qsizetype byteIdx = i >> 3;
qsizetype bitIdx = i & 7;
return R{ ba.d[1 + byteIdx], uchar(1U << bitIdx) };
}
public: public:
inline QBitArray() noexcept {} inline QBitArray() noexcept {}
explicit QBitArray(qsizetype size, bool val = false); explicit QBitArray(qsizetype size, bool val = false);
@ -41,11 +53,21 @@ public:
inline bool isDetached() const { return d.isDetached(); } inline bool isDetached() const { return d.isDetached(); }
inline void clear() { d.clear(); } inline void clear() { d.clear(); }
bool testBit(qsizetype i) const; bool testBit(qsizetype i) const
void setBit(qsizetype i); { auto r = bitLocation(*this, i); return r.byte & r.bitMask; }
void setBit(qsizetype i, bool val); void setBit(qsizetype i)
void clearBit(qsizetype i); { auto r = bitLocation(*this, i); r.byte |= r.bitMask; }
bool toggleBit(qsizetype i); void setBit(qsizetype i, bool val)
{ if (val) setBit(i); else clearBit(i); }
void clearBit(qsizetype i)
{ auto r = bitLocation(*this, i); r.byte &= ~r.bitMask; }
bool toggleBit(qsizetype i)
{
auto r = bitLocation(*this, i);
bool cl = r.byte & r.bitMask;
r.byte ^= r.bitMask;
return cl;
}
bool at(qsizetype i) const; bool at(qsizetype i) const;
QBitRef operator[](qsizetype i); QBitRef operator[](qsizetype i);
@ -81,26 +103,6 @@ Q_CORE_EXPORT QBitArray operator&(const QBitArray &, const QBitArray &);
Q_CORE_EXPORT QBitArray operator|(const QBitArray &, const QBitArray &); Q_CORE_EXPORT QBitArray operator|(const QBitArray &, const QBitArray &);
Q_CORE_EXPORT QBitArray operator^(const QBitArray &, const QBitArray &); Q_CORE_EXPORT QBitArray operator^(const QBitArray &, const QBitArray &);
inline bool QBitArray::testBit(qsizetype i) const
{ Q_ASSERT(size_t(i) < size_t(size()));
return (*(reinterpret_cast<const uchar*>(d.constData())+1+(i>>3)) & (1 << (i & 7))) != 0; }
inline void QBitArray::setBit(qsizetype i)
{ Q_ASSERT(size_t(i) < size_t(size()));
*(reinterpret_cast<uchar*>(d.data())+1+(i>>3)) |= uchar(1 << (i & 7)); }
inline void QBitArray::clearBit(qsizetype i)
{ Q_ASSERT(size_t(i) < size_t(size()));
*(reinterpret_cast<uchar*>(d.data())+1+(i>>3)) &= ~uchar(1 << (i & 7)); }
inline void QBitArray::setBit(qsizetype i, bool val)
{ if (val) setBit(i); else clearBit(i); }
inline bool QBitArray::toggleBit(qsizetype i)
{ Q_ASSERT(size_t(i) < size_t(size()));
uchar b = uchar(1<<(i&7)); uchar* p = reinterpret_cast<uchar*>(d.data())+1+(i>>3);
uchar c = uchar(*p&b); *p^=b; return c!=0; }
inline bool QBitArray::operator[](qsizetype i) const { return testBit(i); } inline bool QBitArray::operator[](qsizetype i) const { return testBit(i); }
inline bool QBitArray::at(qsizetype i) const { return testBit(i); } inline bool QBitArray::at(qsizetype i) const { return testBit(i); }