QCryptographicHash: don't present the same data over and over again
Need to decrement 'remaining' (check), but also increment data (meep). Testing is a bit complicated, as most algorithms are just too slow to fit into the 5min QTestLib timeout. Picked the fast ones and Sha512 (which completes here in < 17s, with threads), at least. Amends e12577b56396cca0df05f88f8787706a3a12c82d. [ChangeLog][QtCore][QCryptographicHash] Fixed a bug where presenting more than 4GiB in a single addData() call would calculate the wrong result(). Change-Id: Ic72916ebc33ba087d58225af6d8240e46e41f434 Reviewed-by: Lars Knoll <lars.knoll@qt.io> (cherry picked from commit 35453446a511366e1250858b249e36c80b6ad044) Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
This commit is contained in:
parent
b26f39b946
commit
3fa9c19481
@ -363,10 +363,8 @@ void QCryptographicHash::addData(const char *data, qsizetype length)
|
||||
// feed the data UINT_MAX bytes at a time, as some of the methods below
|
||||
// take a uint (of course, feeding more than 4G of data into the hashing
|
||||
// functions will be pretty slow anyway)
|
||||
qsizetype remaining = length;
|
||||
while (remaining) {
|
||||
for (auto remaining = length; remaining; remaining -= length, data += length) {
|
||||
length = qMin(qsizetype(std::numeric_limits<uint>::max()), remaining);
|
||||
remaining -= length;
|
||||
#else
|
||||
{
|
||||
#endif
|
||||
|
@ -29,9 +29,14 @@
|
||||
|
||||
#include <QtCore/QCoreApplication>
|
||||
#include <QTest>
|
||||
#include <QScopeGuard>
|
||||
#include <QCryptographicHash>
|
||||
#include <QtCore/QMetaEnum>
|
||||
|
||||
#if QT_CONFIG(cxx11_future)
|
||||
# include <thread>
|
||||
#endif
|
||||
|
||||
Q_DECLARE_METATYPE(QCryptographicHash::Algorithm)
|
||||
|
||||
class tst_QCryptographicHash : public QObject
|
||||
@ -51,6 +56,11 @@ private slots:
|
||||
void files();
|
||||
void hashLength_data();
|
||||
void hashLength();
|
||||
// keep last
|
||||
void moreThan4GiBOfData_data();
|
||||
void moreThan4GiBOfData();
|
||||
private:
|
||||
std::vector<char> large;
|
||||
};
|
||||
|
||||
void tst_QCryptographicHash::repeated_result_data()
|
||||
@ -419,5 +429,79 @@ void tst_QCryptographicHash::hashLength()
|
||||
QCOMPARE(QCryptographicHash::hashLength(algorithm), output.length());
|
||||
}
|
||||
|
||||
void tst_QCryptographicHash::moreThan4GiBOfData_data()
|
||||
{
|
||||
#if QT_POINTER_SIZE > 4
|
||||
QElapsedTimer timer;
|
||||
timer.start();
|
||||
const size_t GiB = 1024 * 1024 * 1024;
|
||||
try {
|
||||
large.resize(4 * GiB + 1, '\0');
|
||||
} catch (const std::bad_alloc &) {
|
||||
QSKIP("Could not allocate 4GiB plus one byte of RAM.");
|
||||
}
|
||||
QCOMPARE(large.size(), 4 * GiB + 1);
|
||||
large.back() = '\1';
|
||||
qDebug("created dataset in %lld ms", timer.elapsed());
|
||||
|
||||
QTest::addColumn<QCryptographicHash::Algorithm>("algorithm");
|
||||
auto me = QMetaEnum::fromType<QCryptographicHash::Algorithm>();
|
||||
auto row = [me] (QCryptographicHash::Algorithm algo) {
|
||||
QTest::addRow("%s", me.valueToKey(int(algo))) << algo;
|
||||
};
|
||||
// these are reasonably fast (O(secs))
|
||||
row(QCryptographicHash::Md4);
|
||||
row(QCryptographicHash::Md5);
|
||||
row(QCryptographicHash::Sha1);
|
||||
// this is already significantly slower, but important (O(min)
|
||||
row(QCryptographicHash::Sha512);
|
||||
// the rest is just too slow
|
||||
#else
|
||||
QSKIP("This test is 64-bit only.");
|
||||
#endif
|
||||
}
|
||||
|
||||
void tst_QCryptographicHash::moreThan4GiBOfData()
|
||||
{
|
||||
QFETCH(const QCryptographicHash::Algorithm, algorithm);
|
||||
|
||||
# if QT_CONFIG(cxx11_future)
|
||||
using MaybeThread = std::thread;
|
||||
# else
|
||||
struct MaybeThread {
|
||||
std::function<void()> func;
|
||||
void join() { func(); }
|
||||
};
|
||||
# endif
|
||||
|
||||
QElapsedTimer timer;
|
||||
timer.start();
|
||||
const auto sg = qScopeGuard([&] {
|
||||
qDebug() << algorithm << "test finished in" << timer.restart() << "ms";
|
||||
});
|
||||
|
||||
const auto begin = large.data();
|
||||
const auto mid = begin + large.size() / 2;
|
||||
const auto end = begin + large.size();
|
||||
|
||||
QByteArray single;
|
||||
QByteArray chunked;
|
||||
|
||||
auto t = MaybeThread{[&] {
|
||||
QCryptographicHash h(algorithm);
|
||||
h.addData(begin, end - begin);
|
||||
single = h.result();
|
||||
}};
|
||||
{
|
||||
QCryptographicHash h(algorithm);
|
||||
h.addData(begin, mid - begin);
|
||||
h.addData(mid, end - mid);
|
||||
chunked = h.result();
|
||||
}
|
||||
t.join();
|
||||
|
||||
QCOMPARE(single, chunked);
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QCryptographicHash)
|
||||
#include "tst_qcryptographichash.moc"
|
||||
|
Loading…
x
Reference in New Issue
Block a user