diff --git a/src/corelib/io/qdatastream.h b/src/corelib/io/qdatastream.h index e0a9cccdada..260dd519e3f 100644 --- a/src/corelib/io/qdatastream.h +++ b/src/corelib/io/qdatastream.h @@ -194,6 +194,29 @@ private: int readBlock(char *data, int len); }; +namespace QtPrivate { + +class StreamStateSaver +{ +public: + inline StreamStateSaver(QDataStream *s) : stream(s), oldStatus(s->status()) + { + stream->resetStatus(); + } + inline ~StreamStateSaver() + { + if (oldStatus != QDataStream::Ok) { + stream->resetStatus(); + stream->setStatus(oldStatus); + } + } + +private: + QDataStream *stream; + QDataStream::Status oldStatus; +}; + +} // QtPrivate namespace /***************************************************************************** QDataStream inline functions @@ -238,6 +261,8 @@ inline QDataStream &QDataStream::operator<<(quint64 i) template QDataStream& operator>>(QDataStream& s, QList& l) { + QtPrivate::StreamStateSaver stateSaver(&s); + l.clear(); quint32 c; s >> c; @@ -246,10 +271,13 @@ QDataStream& operator>>(QDataStream& s, QList& l) { T t; s >> t; - l.append(t); - if (s.atEnd()) + if (s.status() != QDataStream::Ok) { + l.clear(); break; + } + l.append(t); } + return s; } @@ -265,6 +293,8 @@ QDataStream& operator<<(QDataStream& s, const QList& l) template QDataStream& operator>>(QDataStream& s, QLinkedList& l) { + QtPrivate::StreamStateSaver stateSaver(&s); + l.clear(); quint32 c; s >> c; @@ -272,10 +302,13 @@ QDataStream& operator>>(QDataStream& s, QLinkedList& l) { T t; s >> t; - l.append(t); - if (s.atEnd()) + if (s.status() != QDataStream::Ok) { + l.clear(); break; + } + l.append(t); } + return s; } @@ -292,6 +325,8 @@ QDataStream& operator<<(QDataStream& s, const QLinkedList& l) template QDataStream& operator>>(QDataStream& s, QVector& v) { + QtPrivate::StreamStateSaver stateSaver(&s); + v.clear(); quint32 c; s >> c; @@ -299,8 +334,13 @@ QDataStream& operator>>(QDataStream& s, QVector& v) for(quint32 i = 0; i < c; ++i) { T t; s >> t; + if (s.status() != QDataStream::Ok) { + v.clear(); + break; + } v[i] = t; } + return s; } @@ -316,16 +356,21 @@ QDataStream& operator<<(QDataStream& s, const QVector& v) template QDataStream &operator>>(QDataStream &in, QSet &set) { + QtPrivate::StreamStateSaver stateSaver(&in); + set.clear(); quint32 c; in >> c; for (quint32 i = 0; i < c; ++i) { T t; in >> t; - set << t; - if (in.atEnd()) + if (in.status() != QDataStream::Ok) { + set.clear(); break; + } + set << t; } + return in; } @@ -344,10 +389,9 @@ QDataStream& operator<<(QDataStream &out, const QSet &set) template Q_OUTOFLINE_TEMPLATE QDataStream &operator>>(QDataStream &in, QHash &hash) { - QDataStream::Status oldStatus = in.status(); - in.resetStatus(); - hash.clear(); + QtPrivate::StreamStateSaver stateSaver(&in); + hash.clear(); quint32 n; in >> n; @@ -363,10 +407,6 @@ Q_OUTOFLINE_TEMPLATE QDataStream &operator>>(QDataStream &in, QHash &has if (in.status() != QDataStream::Ok) hash.clear(); - if (oldStatus != QDataStream::Ok) { - in.resetStatus(); - in.setStatus(oldStatus); - } return in; } @@ -390,10 +430,9 @@ template Q_OUTOFLINE_TEMPLATE QDataStream &operator>>(QDataStream &in, QMap &map) #endif { - QDataStream::Status oldStatus = in.status(); - in.resetStatus(); - map.clear(); + QtPrivate::StreamStateSaver stateSaver(&in); + map.clear(); quint32 n; in >> n; @@ -409,10 +448,6 @@ Q_OUTOFLINE_TEMPLATE QDataStream &operator>>(QDataStream &in, QMap &ma } if (in.status() != QDataStream::Ok) map.clear(); - if (oldStatus != QDataStream::Ok) { - in.resetStatus(); - in.setStatus(oldStatus); - } return in; } diff --git a/tests/auto/corelib/io/qdatastream/tst_qdatastream.cpp b/tests/auto/corelib/io/qdatastream/tst_qdatastream.cpp index ea4c5575744..fefe08db304 100644 --- a/tests/auto/corelib/io/qdatastream/tst_qdatastream.cpp +++ b/tests/auto/corelib/io/qdatastream/tst_qdatastream.cpp @@ -2813,10 +2813,11 @@ void tst_QDataStream::status_QHash_QMap() MAP_TEST(QByteArray("\x00\x00\x00\x01\x00\x00\x00\x01", 8), QDataStream::ReadPastEnd, QDataStream::ReadPastEnd, StringHash()); } -#define LIST_TEST(byteArray, expectedStatus, expectedList) \ +#define LIST_TEST(byteArray, initialStatus, expectedStatus, expectedList) \ { \ QByteArray ba = byteArray; \ QDataStream stream(&ba, QIODevice::ReadOnly); \ + stream.setStatus(initialStatus); \ stream >> list; \ QCOMPARE((int)stream.status(), (int)expectedStatus); \ QCOMPARE(list.size(), expectedList.size()); \ @@ -2828,6 +2829,7 @@ void tst_QDataStream::status_QHash_QMap() expectedLinkedList << expectedList.at(i); \ QByteArray ba = byteArray; \ QDataStream stream(&ba, QIODevice::ReadOnly); \ + stream.setStatus(initialStatus); \ stream >> linkedList; \ QCOMPARE((int)stream.status(), (int)expectedStatus); \ QCOMPARE(linkedList.size(), expectedLinkedList.size()); \ @@ -2839,6 +2841,7 @@ void tst_QDataStream::status_QHash_QMap() expectedVector << expectedList.at(i); \ QByteArray ba = byteArray; \ QDataStream stream(&ba, QIODevice::ReadOnly); \ + stream.setStatus(initialStatus); \ stream >> vector; \ QCOMPARE((int)stream.status(), (int)expectedStatus); \ QCOMPARE(vector.size(), expectedVector.size()); \ @@ -2854,8 +2857,49 @@ void tst_QDataStream::status_QLinkedList_QList_QVector() List list; Vector vector; - LIST_TEST(QByteArray(), QDataStream::ReadPastEnd, List()); - LIST_TEST(QByteArray("\x00\x00\x00\x00", 4), QDataStream::Ok, List()); + // ok + { + List listWithEmptyString; + listWithEmptyString.append(""); + + List someList; + someList.append("J"); + someList.append("MN"); + + LIST_TEST(QByteArray("\x00\x00\x00\x00", 4), QDataStream::Ok, QDataStream::Ok, List()); + LIST_TEST(QByteArray("\x00\x00\x00\x01\x00\x00\x00\x00", 8), QDataStream::Ok, QDataStream::Ok, listWithEmptyString); + LIST_TEST(QByteArray("\x00\x00\x00\x02\x00\x00\x00\x02\x00J" + "\x00\x00\x00\x04\x00M\x00N", 18), QDataStream::Ok, QDataStream::Ok, someList); + } + + // past end + { + LIST_TEST(QByteArray(), QDataStream::Ok, QDataStream::ReadPastEnd, List()); + LIST_TEST(QByteArray("\x00", 1), QDataStream::Ok, QDataStream::ReadPastEnd, List()); + LIST_TEST(QByteArray("\x00\x00", 2), QDataStream::Ok, QDataStream::ReadPastEnd, List()); + LIST_TEST(QByteArray("\x00\x00\x00", 3), QDataStream::Ok, QDataStream::ReadPastEnd, List()); + LIST_TEST(QByteArray("\x00\x00\x00\x01", 4), QDataStream::Ok, QDataStream::ReadPastEnd, List()); + for (int i = 4; i < 12; ++i) { + LIST_TEST(QByteArray("\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00", i), QDataStream::Ok, QDataStream::ReadPastEnd, List()); + } + } + + // corrupt data + { + LIST_TEST(QByteArray("\x00\x00\x00\x01\x00\x00\x00\x01", 8), QDataStream::Ok, QDataStream::ReadCorruptData, List()); + LIST_TEST(QByteArray("\x00\x00\x00\x02\x00\x00\x00\x01\x00J" + "\x00\x00\x00\x02\x00M\x00N", 18), QDataStream::Ok, QDataStream::ReadCorruptData, List()); + } + + // test the previously latched error status is not affected by reading + { + List listWithEmptyString; + listWithEmptyString.append(""); + + LIST_TEST(QByteArray("\x00\x00\x00\x01\x00\x00\x00\x00", 8), QDataStream::ReadPastEnd, QDataStream::ReadPastEnd, listWithEmptyString); + LIST_TEST(QByteArray("\x00\x00\x00\x01", 4), QDataStream::ReadCorruptData, QDataStream::ReadCorruptData, List()); + LIST_TEST(QByteArray("\x00\x00\x00\x01\x00\x00\x00\x01", 8), QDataStream::ReadPastEnd, QDataStream::ReadPastEnd, List()); + } } void tst_QDataStream::streamToAndFromQByteArray()