QBitArray: avoid overflow in storage-to-size calculations
Unlike other containers, a QBitArray's size() is not limited by storage, but, esp. on 32-bit platforms, its size_type: A INT_MAX size() QBitArray only requires 256MiB of storage. So we can't rely on "won't happen in practice" here and need to avoid the potential UB (signed overflow) in the (d.size() * 8 - *d.data()) storage-to-logical-size calculation by using unsigned arithmetic. Use the opportunity to Extract Method adjust_head_and_tail(), centralizing the bit fiddling. Pick-to: 6.6 6.5 6.2 5.15 Change-Id: I485eafdf3ce2087a81c683672ff98a43f97c9968 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Thiago Macieira <thiago.macieira@intel.com> (cherry picked from commit 78f8dfc5427457783ceef7d85885cddbec035ebe) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
parent
e69a151573
commit
e576d50d7c
@ -118,6 +118,16 @@ static constexpr qsizetype allocation_size(qsizetype size)
|
||||
return size <= 0 ? 0 : storage_size(size) + 1;
|
||||
}
|
||||
|
||||
static void adjust_head_and_tail(char *data, qsizetype storageSize, qsizetype logicalSize)
|
||||
{
|
||||
quint8 *c = reinterpret_cast<quint8 *>(data);
|
||||
// store the difference between storage and logical size in d[0]:
|
||||
*c = quint8(size_t(storageSize) * 8 - logicalSize);
|
||||
// reset unallocated bits to 0:
|
||||
if (logicalSize & 7)
|
||||
*(c + 1 + logicalSize / 8) &= (1 << (logicalSize & 7)) - 1;
|
||||
}
|
||||
|
||||
/*!
|
||||
Constructs a bit array containing \a size bits. The bits are
|
||||
initialized with \a value, which defaults to false (0).
|
||||
@ -131,9 +141,7 @@ QBitArray::QBitArray(qsizetype size, bool value)
|
||||
|
||||
uchar *c = reinterpret_cast<uchar *>(d.data());
|
||||
memset(c + 1, value ? 0xff : 0, d.size() - 1);
|
||||
*c = d.size() * 8 - size;
|
||||
if (value && size && size & 7)
|
||||
*(c + 1 + size / 8) &= (1 << (size & 7)) - 1;
|
||||
adjust_head_and_tail(d.data(), d.size(), size);
|
||||
}
|
||||
|
||||
/*! \fn qsizetype QBitArray::size() const
|
||||
@ -203,11 +211,9 @@ void QBitArray::resize(qsizetype size)
|
||||
qsizetype s = d.size();
|
||||
d.resize(allocation_size(size));
|
||||
uchar *c = reinterpret_cast<uchar *>(d.data());
|
||||
if (size > (s << 3))
|
||||
if (d.size() > s)
|
||||
memset(c + s, 0, d.size() - s);
|
||||
else if (size & 7)
|
||||
*(c + 1 + size / 8) &= (1 << (size & 7)) - 1;
|
||||
*c = d.size() * 8 - size;
|
||||
adjust_head_and_tail(d.data(), d.size(), size);
|
||||
}
|
||||
}
|
||||
|
||||
@ -306,17 +312,11 @@ QBitArray QBitArray::fromBits(const char *data, qsizetype size)
|
||||
QBitArray result;
|
||||
if (size == 0)
|
||||
return result;
|
||||
qsizetype nbytes = storage_size(size);
|
||||
|
||||
result.d = QByteArray(nbytes + 1, Qt::Uninitialized);
|
||||
char *bits = result.d.data();
|
||||
memcpy(bits + 1, data, nbytes);
|
||||
|
||||
// clear any unused bits from the last byte
|
||||
if (size & 7)
|
||||
bits[nbytes] &= 0xffU >> (8 - (size & 7));
|
||||
|
||||
*bits = result.d.size() * 8 - size;
|
||||
auto &d = result.d;
|
||||
d.resize(allocation_size(size));
|
||||
memcpy(d.data() + 1, data, d.size() - 1);
|
||||
adjust_head_and_tail(d.data(), d.size(), size);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -958,14 +958,13 @@ QDataStream &operator>>(QDataStream &in, QBitArray &ba)
|
||||
allocated += blockSize;
|
||||
}
|
||||
|
||||
qsizetype paddingMask = ~((0x1 << (len & 0x7)) - 1);
|
||||
if (paddingMask != ~0x0 && (ba.d.constData()[ba.d.size() - 1] & paddingMask)) {
|
||||
const auto fromStream = ba.d.back();
|
||||
adjust_head_and_tail(ba.d.data(), ba.d.size(), len);
|
||||
if (ba.d.back() != fromStream) {
|
||||
ba.clear();
|
||||
in.setStatus(QDataStream::ReadCorruptData);
|
||||
return in;
|
||||
}
|
||||
|
||||
*ba.d.data() = ba.d.size() * 8 - len;
|
||||
return in;
|
||||
}
|
||||
#endif // QT_NO_DATASTREAM
|
||||
|
@ -70,8 +70,8 @@ public:
|
||||
|
||||
void swap(QBitArray &other) noexcept { d.swap(other.d); }
|
||||
|
||||
inline qsizetype size() const { return (d.size() << 3) - *d.constData(); }
|
||||
inline qsizetype count() const { return (d.size() << 3) - *d.constData(); }
|
||||
qsizetype size() const { return qsizetype((size_t(d.size()) << 3) - *d.constData()); }
|
||||
qsizetype count() const { return size(); }
|
||||
qsizetype count(bool on) const;
|
||||
|
||||
inline bool isEmpty() const { return d.isEmpty(); }
|
||||
|
Loading…
x
Reference in New Issue
Block a user