QDataStream: do not lose error status while reading containers

Otherwise, the code:

  ds >> s >> hash;

could set the stream status to ReadPastEnd, while deserialization
of the string is failed with ReadCorruptData status.

Proposed solution is to restore a previously latched error status
unconditionally in accordance with QDataStream::setStatus() docs.

Change-Id: Id3a7dccf709b02e5b018efb48d7647ee48fe5124
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
This commit is contained in:
Alex Trotsenko 2016-06-14 18:51:02 +03:00
parent 49491dd678
commit 3c87c82e52
2 changed files with 25 additions and 14 deletions

View File

@ -363,8 +363,10 @@ Q_OUTOFLINE_TEMPLATE QDataStream &operator>>(QDataStream &in, QHash<Key, T> &has
if (in.status() != QDataStream::Ok)
hash.clear();
if (oldStatus != QDataStream::Ok)
if (oldStatus != QDataStream::Ok) {
in.resetStatus();
in.setStatus(oldStatus);
}
return in;
}
@ -407,8 +409,10 @@ Q_OUTOFLINE_TEMPLATE QDataStream &operator>>(QDataStream &in, QMap<aKey, aT> &ma
}
if (in.status() != QDataStream::Ok)
map.clear();
if (oldStatus != QDataStream::Ok)
if (oldStatus != QDataStream::Ok) {
in.resetStatus();
in.setStatus(oldStatus);
}
return in;
}

View File

@ -2748,10 +2748,11 @@ void tst_QDataStream::status_QBitArray()
QCOMPARE(str, expectedString);
}
#define MAP_TEST(byteArray, expectedStatus, expectedHash) \
#define MAP_TEST(byteArray, initialStatus, expectedStatus, expectedHash) \
{ \
QByteArray ba = byteArray; \
QDataStream stream(&ba, QIODevice::ReadOnly); \
stream.setStatus(initialStatus); \
stream >> hash; \
QCOMPARE((int)stream.status(), (int)expectedStatus); \
QCOMPARE(hash.size(), expectedHash.size()); \
@ -2764,6 +2765,7 @@ void tst_QDataStream::status_QBitArray()
for (; it != expectedHash.constEnd(); ++it) \
expectedMap.insert(it.key(), it.value()); \
QDataStream stream(&ba, QIODevice::ReadOnly); \
stream.setStatus(initialStatus); \
stream >> map; \
QCOMPARE((int)stream.status(), (int)expectedStatus); \
QCOMPARE(map.size(), expectedMap.size()); \
@ -2785,25 +2787,30 @@ void tst_QDataStream::status_QHash_QMap()
hash2.insert("L", "MN");
// ok
MAP_TEST(QByteArray("\x00\x00\x00\x00", 4), QDataStream::Ok, StringHash());
MAP_TEST(QByteArray("\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00", 12), QDataStream::Ok, hash1);
MAP_TEST(QByteArray("\x00\x00\x00\x00", 4), QDataStream::Ok, QDataStream::Ok, StringHash());
MAP_TEST(QByteArray("\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00", 12), QDataStream::Ok, QDataStream::Ok, hash1);
MAP_TEST(QByteArray("\x00\x00\x00\x02\x00\x00\x00\x02\x00J\x00\x00\x00\x02\x00K"
"\x00\x00\x00\x02\x00L\x00\x00\x00\x04\x00M\x00N", 30), QDataStream::Ok, hash2);
"\x00\x00\x00\x02\x00L\x00\x00\x00\x04\x00M\x00N", 30), QDataStream::Ok, QDataStream::Ok, hash2);
// past end
MAP_TEST(QByteArray(), QDataStream::ReadPastEnd, StringHash());
MAP_TEST(QByteArray("\x00", 1), QDataStream::ReadPastEnd, StringHash());
MAP_TEST(QByteArray("\x00\x00", 2), QDataStream::ReadPastEnd, StringHash());
MAP_TEST(QByteArray("\x00\x00\x00", 3), QDataStream::ReadPastEnd, StringHash());
MAP_TEST(QByteArray("\x00\x00\x00\x01", 4), QDataStream::ReadPastEnd, StringHash());
MAP_TEST(QByteArray(), QDataStream::Ok, QDataStream::ReadPastEnd, StringHash());
MAP_TEST(QByteArray("\x00", 1), QDataStream::Ok, QDataStream::ReadPastEnd, StringHash());
MAP_TEST(QByteArray("\x00\x00", 2), QDataStream::Ok, QDataStream::ReadPastEnd, StringHash());
MAP_TEST(QByteArray("\x00\x00\x00", 3), QDataStream::Ok, QDataStream::ReadPastEnd, StringHash());
MAP_TEST(QByteArray("\x00\x00\x00\x01", 4), QDataStream::Ok, QDataStream::ReadPastEnd, StringHash());
for (int i = 4; i < 12; ++i) {
MAP_TEST(QByteArray("\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00", i), QDataStream::ReadPastEnd, StringHash());
MAP_TEST(QByteArray("\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00", i), QDataStream::Ok, QDataStream::ReadPastEnd, StringHash());
}
// corrupt data
MAP_TEST(QByteArray("\x00\x00\x00\x01\x00\x00\x00\x01", 8), QDataStream::ReadCorruptData, StringHash());
MAP_TEST(QByteArray("\x00\x00\x00\x01\x00\x00\x00\x01", 8), QDataStream::Ok, QDataStream::ReadCorruptData, StringHash());
MAP_TEST(QByteArray("\x00\x00\x00\x02\x00\x00\x00\x01\x00J\x00\x00\x00\x01\x00K"
"\x00\x00\x00\x01\x00L\x00\x00\x00\x02\x00M\x00N", 30), QDataStream::ReadCorruptData, StringHash());
"\x00\x00\x00\x01\x00L\x00\x00\x00\x02\x00M\x00N", 30), QDataStream::Ok, QDataStream::ReadCorruptData, StringHash());
// test the previously latched error status is not affected by reading
MAP_TEST(QByteArray("\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00", 12), QDataStream::ReadPastEnd, QDataStream::ReadPastEnd, hash1);
MAP_TEST(QByteArray("\x00\x00\x00\x01", 4), QDataStream::ReadCorruptData, QDataStream::ReadCorruptData, StringHash());
MAP_TEST(QByteArray("\x00\x00\x00\x01\x00\x00\x00\x01", 8), QDataStream::ReadPastEnd, QDataStream::ReadPastEnd, StringHash());
}
#define LIST_TEST(byteArray, expectedStatus, expectedList) \