summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoão Abecasis <joao.abecasis@nokia.com>2012-03-29 00:24:50 +0200
committerQt by Nokia <qt-info@nokia.com>2012-03-30 11:21:34 +0200
commit4ef5a6269c1465662ea3872596ba284a13cce25e (patch)
tree4297badfef7832b9bee0ba6ce4b4163726f60e40
parentbe4554d934bb443363911339de25aa160fe1c2e8 (diff)
Add tests to verify QByteArray's zero termination
For data allocated and maintained by QByteArray, there's a guarantee that data() is null-terminated. This holds true even for null and empty, where logically the terminating character should never be dereferenced. For tests that modify or generate QByteArrays, this ensures the invariant is kept. In the toFromHex() text, const-ness of temporary variables was dropped to enable the test macro to be used, as the qualification didn't add much to the test otherwise. Change-Id: I7ee52e79e3a9df7de18c743f3698dab688e6bf0e Reviewed-by: Jędrzej Nowacki <jedrzej.nowacki@nokia.com>
-rw-r--r--tests/auto/corelib/tools/qbytearray/tst_qbytearray.cpp128
1 files changed, 123 insertions, 5 deletions
diff --git a/tests/auto/corelib/tools/qbytearray/tst_qbytearray.cpp b/tests/auto/corelib/tools/qbytearray/tst_qbytearray.cpp
index 2c8aa4d62a..fe9b5f67c4 100644
--- a/tests/auto/corelib/tools/qbytearray/tst_qbytearray.cpp
+++ b/tests/auto/corelib/tools/qbytearray/tst_qbytearray.cpp
@@ -147,8 +147,40 @@ private slots:
void movablity_data();
void movablity();
void literals();
+
+ void zeroTermination_data();
+ void zeroTermination();
};
+// Except for QByteArrays initialized with fromRawData(), QByteArray ensures
+// that data() is null-terminated. VERIFY_ZERO_TERMINATION checks that
+// invariant and goes further by testing that the null-character is in writable
+// memory allocated by QByteArray. If the invariant is broken, tools like
+// valgrind should be able to detect this.
+#define VERIFY_ZERO_TERMINATION(ba) \
+ do { \
+ /* Statics could be anything, as can fromRawData() strings */ \
+ QByteArray::DataPtr baDataPtr = ba.data_ptr(); \
+ if (!baDataPtr->ref.isStatic() \
+ && baDataPtr->offset == QByteArray().data_ptr()->offset) { \
+ int baSize = ba.size(); \
+ QCOMPARE(ba.constData()[baSize], '\0'); \
+ \
+ QByteArray baCopy(ba.constData(), baSize); \
+ if (!baDataPtr->ref.isShared()) { \
+ /* Don't detach, assumes no setSharable support */ \
+ char *baData = ba.data(); \
+ baData[baSize] = 'x'; \
+ \
+ QCOMPARE(ba.constData()[baSize], 'x'); \
+ QCOMPARE(ba, baCopy); \
+ \
+ baData[baSize] = '\0'; /* Sanity restored */ \
+ } \
+ } \
+ } while (false) \
+ /**/
+
struct StaticByteArrays {
struct Standard {
QByteArrayData data;
@@ -224,8 +256,13 @@ void tst_QByteArray::qCompress_data()
void tst_QByteArray::qCompress()
{
QFETCH( QByteArray, ba );
+
QByteArray compressed = ::qCompress( ba );
- QTEST( ::qUncompress( compressed ), "ba" );
+ QByteArray uncompressed = ::qUncompress(compressed);
+
+ QCOMPARE(uncompressed, ba);
+ VERIFY_ZERO_TERMINATION(compressed);
+ VERIFY_ZERO_TERMINATION(uncompressed);
}
void tst_QByteArray::qUncompressCorruptedData_data()
@@ -257,9 +294,11 @@ void tst_QByteArray::qUncompressCorruptedData()
QByteArray res;
res = ::qUncompress(in);
QCOMPARE(res, QByteArray());
+ VERIFY_ZERO_TERMINATION(res);
res = ::qUncompress(in + "blah");
QCOMPARE(res, QByteArray());
+ VERIFY_ZERO_TERMINATION(res);
#else
QSKIP("This test freezes on this platform");
#endif
@@ -269,7 +308,7 @@ void tst_QByteArray::qCompressionZeroTermination()
{
QString s = "Hello, I'm a string.";
QByteArray ba = ::qUncompress(::qCompress(s.toLocal8Bit()));
- QVERIFY((int) *(ba.data() + ba.size()) == 0);
+ VERIFY_ZERO_TERMINATION(ba);
}
#endif
@@ -289,6 +328,7 @@ void tst_QByteArray::constByteArray()
QVERIFY(cba.constData()[1] == 'b');
QVERIFY(cba.constData()[2] == 'c');
QVERIFY(cba.constData()[3] == '\0');
+ VERIFY_ZERO_TERMINATION(cba);
}
void tst_QByteArray::leftJustified()
@@ -506,9 +546,11 @@ void tst_QByteArray::base64()
QByteArray arr = QByteArray::fromBase64(base64);
QCOMPARE(arr, rawdata);
+ VERIFY_ZERO_TERMINATION(arr);
QByteArray arr64 = rawdata.toBase64();
QCOMPARE(arr64, base64);
+ VERIFY_ZERO_TERMINATION(arr64);
}
//different from the previous test as the input are invalid
@@ -733,17 +775,24 @@ void tst_QByteArray::chop()
src.chop(choplength);
QCOMPARE(src, expected);
+ VERIFY_ZERO_TERMINATION(src);
}
void tst_QByteArray::prepend()
{
QByteArray ba("foo");
QCOMPARE(ba.prepend((char*)0), QByteArray("foo"));
+ VERIFY_ZERO_TERMINATION(ba);
QCOMPARE(ba.prepend(QByteArray()), QByteArray("foo"));
+ VERIFY_ZERO_TERMINATION(ba);
QCOMPARE(ba.prepend("1"), QByteArray("1foo"));
+ VERIFY_ZERO_TERMINATION(ba);
QCOMPARE(ba.prepend(QByteArray("2")), QByteArray("21foo"));
+ VERIFY_ZERO_TERMINATION(ba);
QCOMPARE(ba.prepend('3'), QByteArray("321foo"));
+ VERIFY_ZERO_TERMINATION(ba);
QCOMPARE(ba.prepend("\0 ", 2), QByteArray::fromRawData("\0 321foo", 8));
+ VERIFY_ZERO_TERMINATION(ba);
}
void tst_QByteArray::prependExtended_data()
@@ -767,11 +816,17 @@ void tst_QByteArray::prependExtended()
QCOMPARE(QByteArray("").prepend(array), QByteArray("data"));
QCOMPARE(array.prepend((char*)0), QByteArray("data"));
+ VERIFY_ZERO_TERMINATION(array);
QCOMPARE(array.prepend(QByteArray()), QByteArray("data"));
+ VERIFY_ZERO_TERMINATION(array);
QCOMPARE(array.prepend("1"), QByteArray("1data"));
+ VERIFY_ZERO_TERMINATION(array);
QCOMPARE(array.prepend(QByteArray("2")), QByteArray("21data"));
+ VERIFY_ZERO_TERMINATION(array);
QCOMPARE(array.prepend('3'), QByteArray("321data"));
+ VERIFY_ZERO_TERMINATION(array);
QCOMPARE(array.prepend("\0 ", 2), QByteArray::fromRawData("\0 321data", 9));
+ VERIFY_ZERO_TERMINATION(array);
QCOMPARE(array.size(), 9);
}
@@ -779,12 +834,19 @@ void tst_QByteArray::append()
{
QByteArray ba("foo");
QCOMPARE(ba.append((char*)0), QByteArray("foo"));
+ VERIFY_ZERO_TERMINATION(ba);
QCOMPARE(ba.append(QByteArray()), QByteArray("foo"));
+ VERIFY_ZERO_TERMINATION(ba);
QCOMPARE(ba.append("1"), QByteArray("foo1"));
+ VERIFY_ZERO_TERMINATION(ba);
QCOMPARE(ba.append(QByteArray("2")), QByteArray("foo12"));
+ VERIFY_ZERO_TERMINATION(ba);
QCOMPARE(ba.append('3'), QByteArray("foo123"));
+ VERIFY_ZERO_TERMINATION(ba);
QCOMPARE(ba.append("\0"), QByteArray("foo123"));
+ VERIFY_ZERO_TERMINATION(ba);
QCOMPARE(ba.append("\0", 1), QByteArray::fromRawData("foo123\0", 7));
+ VERIFY_ZERO_TERMINATION(ba);
QCOMPARE(ba.size(), 7);
}
@@ -801,12 +863,19 @@ void tst_QByteArray::appendExtended()
QCOMPARE(QByteArray("").append(array), QByteArray("data"));
QCOMPARE(array.append((char*)0), QByteArray("data"));
+ VERIFY_ZERO_TERMINATION(array);
QCOMPARE(array.append(QByteArray()), QByteArray("data"));
+ VERIFY_ZERO_TERMINATION(array);
QCOMPARE(array.append("1"), QByteArray("data1"));
+ VERIFY_ZERO_TERMINATION(array);
QCOMPARE(array.append(QByteArray("2")), QByteArray("data12"));
+ VERIFY_ZERO_TERMINATION(array);
QCOMPARE(array.append('3'), QByteArray("data123"));
+ VERIFY_ZERO_TERMINATION(array);
QCOMPARE(array.append("\0"), QByteArray("data123"));
+ VERIFY_ZERO_TERMINATION(array);
QCOMPARE(array.append("\0", 1), QByteArray::fromRawData("data123\0", 8));
+ VERIFY_ZERO_TERMINATION(array);
QCOMPARE(array.size(), 8);
}
@@ -814,22 +883,28 @@ void tst_QByteArray::insert()
{
QByteArray ba("Meal");
QCOMPARE(ba.insert(1, QByteArray("ontr")), QByteArray("Montreal"));
+ VERIFY_ZERO_TERMINATION(ba);
QCOMPARE(ba.insert(ba.size(), "foo"), QByteArray("Montrealfoo"));
+ VERIFY_ZERO_TERMINATION(ba);
ba = QByteArray("13");
QCOMPARE(ba.insert(1, QByteArray("2")), QByteArray("123"));
+ VERIFY_ZERO_TERMINATION(ba);
ba = "ac";
QCOMPARE(ba.insert(1, 'b'), QByteArray("abc"));
QCOMPARE(ba.size(), 3);
+ VERIFY_ZERO_TERMINATION(ba);
ba = "ikl";
QCOMPARE(ba.insert(1, "j"), QByteArray("ijkl"));
QCOMPARE(ba.size(), 4);
+ VERIFY_ZERO_TERMINATION(ba);
ba = "ab";
QCOMPARE(ba.insert(1, "\0X\0", 3), QByteArray::fromRawData("a\0X\0b", 5));
QCOMPARE(ba.size(), 5);
+ VERIFY_ZERO_TERMINATION(ba);
}
void tst_QByteArray::insertExtended_data()
@@ -842,6 +917,7 @@ void tst_QByteArray::insertExtended()
QFETCH(QByteArray, array);
QCOMPARE(array.insert(1, "i"), QByteArray("diata"));
QCOMPARE(array.size(), 5);
+ VERIFY_ZERO_TERMINATION(array);
}
void tst_QByteArray::remove_data()
@@ -872,6 +948,7 @@ void tst_QByteArray::remove()
QFETCH(int, length);
QFETCH(QByteArray, expected);
QCOMPARE(src.remove(position, length), expected);
+ VERIFY_ZERO_TERMINATION(src);
}
void tst_QByteArray::replace_data()
@@ -913,6 +990,8 @@ void tst_QByteArray::replace()
QCOMPARE(str1.replace(pos, len, after).constData(), expected.constData());
QCOMPARE(str2.replace(pos, len, after.data()), expected);
+ VERIFY_ZERO_TERMINATION(str1);
+ VERIFY_ZERO_TERMINATION(str2);
}
void tst_QByteArray::replaceWithSpecifiedLength()
@@ -925,6 +1004,7 @@ void tst_QByteArray::replaceWithSpecifiedLength()
const char _expected[] = "zxc\0vbcdefghjk";
QByteArray expected(_expected,sizeof(_expected)-1);
QCOMPARE(ba,expected);
+ VERIFY_ZERO_TERMINATION(ba);
}
void tst_QByteArray::indexOf_data()
@@ -1227,6 +1307,7 @@ void tst_QByteArray::appendAfterFromRawData()
data[0] = 'Y';
}
QVERIFY(arr.at(0) == 'X');
+ VERIFY_ZERO_TERMINATION(arr);
}
void tst_QByteArray::toFromHex_data()
@@ -1298,15 +1379,17 @@ void tst_QByteArray::toFromHex()
QFETCH(QByteArray, hex_alt1);
{
- const QByteArray th = str.toHex();
+ QByteArray th = str.toHex();
QCOMPARE(th.size(), hex.size());
QCOMPARE(th, hex);
+ VERIFY_ZERO_TERMINATION(th);
}
{
- const QByteArray fh = QByteArray::fromHex(hex);
+ QByteArray fh = QByteArray::fromHex(hex);
QCOMPARE(fh.size(), str.size());
QCOMPARE(fh, str);
+ VERIFY_ZERO_TERMINATION(fh);
}
QCOMPARE(QByteArray::fromHex(hex_alt1), str);
@@ -1319,14 +1402,17 @@ void tst_QByteArray::toFromPercentEncoding()
QByteArray data = arr.toPercentEncoding();
QCOMPARE(QString(data), QString("Qt%20is%20great%21"));
QCOMPARE(QByteArray::fromPercentEncoding(data), arr);
+ VERIFY_ZERO_TERMINATION(data);
data = arr.toPercentEncoding("! ", "Qt");
QCOMPARE(QString(data), QString("%51%74 is grea%74!"));
QCOMPARE(QByteArray::fromPercentEncoding(data), arr);
+ VERIFY_ZERO_TERMINATION(data);
data = arr.toPercentEncoding(QByteArray(), "abcdefghijklmnopqrstuvwxyz", 'Q');
QCOMPARE(QString(data), QString("Q51Q74Q20Q69Q73Q20Q67Q72Q65Q61Q74Q21"));
QCOMPARE(QByteArray::fromPercentEncoding(data, 'Q'), arr);
+ VERIFY_ZERO_TERMINATION(data);
// verify that to/from percent encoding preserves nullity
arr = "";
@@ -1336,6 +1422,7 @@ void tst_QByteArray::toFromPercentEncoding()
QVERIFY(!arr.toPercentEncoding().isNull());
QVERIFY(QByteArray::fromPercentEncoding("").isEmpty());
QVERIFY(!QByteArray::fromPercentEncoding("").isNull());
+ VERIFY_ZERO_TERMINATION(arr);
arr = QByteArray();
QVERIFY(arr.isEmpty());
@@ -1344,6 +1431,7 @@ void tst_QByteArray::toFromPercentEncoding()
QVERIFY(arr.toPercentEncoding().isNull());
QVERIFY(QByteArray::fromPercentEncoding(QByteArray()).isEmpty());
QVERIFY(QByteArray::fromPercentEncoding(QByteArray()).isNull());
+ VERIFY_ZERO_TERMINATION(arr);
}
void tst_QByteArray::fromPercentEncoding_data()
@@ -1585,6 +1673,9 @@ void tst_QByteArray::repeated() const
QFETCH(int, count);
QCOMPARE(string.repeated(count), expected);
+
+ QByteArray repeats = string.repeated(count);
+ VERIFY_ZERO_TERMINATION(repeats);
}
void tst_QByteArray::repeated_data() const
@@ -1676,6 +1767,7 @@ void tst_QByteArray::byteRefDetaching() const
copy[0] = 'S';
QCOMPARE(str, QByteArray("str"));
+ VERIFY_ZERO_TERMINATION(copy);
}
{
@@ -1684,6 +1776,7 @@ void tst_QByteArray::byteRefDetaching() const
str[0] = 'S';
QCOMPARE(buf[0], char('s'));
+ VERIFY_ZERO_TERMINATION(str);
}
{
@@ -1694,6 +1787,7 @@ void tst_QByteArray::byteRefDetaching() const
str[0] = 'S';
QCOMPARE(buf[0], char('s'));
+ VERIFY_ZERO_TERMINATION(str);
}
}
@@ -1703,19 +1797,25 @@ void tst_QByteArray::reserve()
QByteArray qba;
qba.reserve(capacity);
QVERIFY(qba.capacity() == capacity);
- char *data = qba.data();
+ VERIFY_ZERO_TERMINATION(qba);
+ char *data = qba.data();
for (int i = 0; i < capacity; i++) {
qba.resize(i);
QVERIFY(capacity == qba.capacity());
QVERIFY(data == qba.data());
+ VERIFY_ZERO_TERMINATION(qba);
}
QByteArray nil1, nil2;
nil1.reserve(0);
+ VERIFY_ZERO_TERMINATION(nil1);
nil2.squeeze();
+ VERIFY_ZERO_TERMINATION(nil2);
nil1.squeeze();
+ VERIFY_ZERO_TERMINATION(nil1);
nil2.reserve(0);
+ VERIFY_ZERO_TERMINATION(nil2);
}
void tst_QByteArray::reserveExtended_data()
@@ -1726,12 +1826,16 @@ void tst_QByteArray::reserveExtended_data()
void tst_QByteArray::reserveExtended()
{
QFETCH(QByteArray, array);
+
array.reserve(1024);
QVERIFY(array.capacity() == 1024);
QCOMPARE(array, QByteArray("data"));
+ VERIFY_ZERO_TERMINATION(array);
+
array.squeeze();
QCOMPARE(array, QByteArray("data"));
QCOMPARE(array.capacity(), array.size());
+ VERIFY_ZERO_TERMINATION(array);
}
void tst_QByteArray::movablity_data()
@@ -1824,6 +1928,7 @@ void tst_QByteArray::literals()
QVERIFY(str == "abcd");
QVERIFY(str.data_ptr()->ref.isStatic());
QVERIFY(str.data_ptr()->offset == sizeof(QByteArrayData));
+ VERIFY_ZERO_TERMINATION(str);
const char *s = str.constData();
QByteArray str2 = str;
@@ -1831,14 +1936,27 @@ void tst_QByteArray::literals()
// detach on non const access
QVERIFY(str.data() != s);
+ VERIFY_ZERO_TERMINATION(str);
QVERIFY(str2.constData() == s);
QVERIFY(str2.data() != s);
+ VERIFY_ZERO_TERMINATION(str2);
#else
QSKIP("Only tested on c++0x compliant compiler or gcc");
#endif
}
+void tst_QByteArray::zeroTermination_data()
+{
+ movablity_data();
+}
+
+void tst_QByteArray::zeroTermination()
+{
+ QFETCH(QByteArray, array);
+ VERIFY_ZERO_TERMINATION(array);
+}
+
const char globalChar = '1';
QTEST_APPLESS_MAIN(tst_QByteArray)