2022-08-19 15:59:36 +02:00
|
|
|
// Copyright (C) 2016 The Qt Company Ltd.
|
2022-12-21 10:12:09 +01:00
|
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
2011-03-04 12:15:18 +01:00
|
|
|
|
2016-12-06 12:05:05 +01:00
|
|
|
#include "valgrindmemcheckparsertest.h"
|
2011-03-04 12:15:18 +01:00
|
|
|
|
2023-08-05 10:33:26 +02:00
|
|
|
#include "valgrindrunner.h"
|
|
|
|
|
#include "xmlprotocol/error.h"
|
2016-12-06 12:05:05 +01:00
|
|
|
#include "xmlprotocol/frame.h"
|
|
|
|
|
#include "xmlprotocol/parser.h"
|
|
|
|
|
#include "xmlprotocol/stack.h"
|
2023-08-05 10:33:26 +02:00
|
|
|
#include "xmlprotocol/status.h"
|
2016-12-06 12:05:05 +01:00
|
|
|
#include "xmlprotocol/suppression.h"
|
|
|
|
|
|
2022-10-24 23:44:24 +02:00
|
|
|
#include <projectexplorer/runcontrol.h>
|
2011-03-04 12:15:18 +01:00
|
|
|
|
|
|
|
|
#include <QFileInfo>
|
|
|
|
|
#include <QTcpServer>
|
2023-08-05 10:33:26 +02:00
|
|
|
#include <QTest>
|
2011-03-04 12:15:18 +01:00
|
|
|
|
2019-06-20 17:19:12 +02:00
|
|
|
using namespace Utils;
|
2011-03-04 12:15:18 +01:00
|
|
|
using namespace Valgrind::XmlProtocol;
|
|
|
|
|
|
|
|
|
|
QT_BEGIN_NAMESPACE
|
|
|
|
|
namespace QTest {
|
|
|
|
|
|
|
|
|
|
template<>
|
2023-07-25 16:29:36 +02:00
|
|
|
inline bool qCompare(int const &t1, MemcheckError const &t2,
|
2011-03-04 12:15:18 +01:00
|
|
|
char const *actual, char const *expected, char const *file, int line)
|
|
|
|
|
{
|
|
|
|
|
return qCompare(t1, int(t2), actual, expected, file, line);
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-09 15:54:29 +01:00
|
|
|
inline bool qCompare(const QString &t1, char const *t2,
|
|
|
|
|
char const *actual, char const *expected, char const *file, int line)
|
|
|
|
|
{
|
|
|
|
|
return qCompare(t1, QString::fromLatin1(t2), actual, expected, file, line);
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-04 12:15:18 +01:00
|
|
|
} // namespace QTest
|
|
|
|
|
QT_END_NAMESPACE
|
|
|
|
|
|
2023-08-05 10:33:26 +02:00
|
|
|
namespace Valgrind::Test {
|
2011-03-04 12:15:18 +01:00
|
|
|
|
2023-08-05 10:33:26 +02:00
|
|
|
static void dumpError(const Error &e)
|
2011-03-04 12:15:18 +01:00
|
|
|
{
|
|
|
|
|
qDebug() << e.kind() << e.leakedBlocks() << e.leakedBytes() << e.what() << e.tid() << e.unique();
|
|
|
|
|
qDebug() << "stacks:" << e.stacks().size();
|
2016-12-06 12:05:05 +01:00
|
|
|
for (const Stack &s : e.stacks()) {
|
2011-03-04 12:15:18 +01:00
|
|
|
qDebug() << s.auxWhat() << s.directory() << s.file() << s.line() << s.helgrindThreadId();
|
|
|
|
|
qDebug() << "frames:";
|
2016-12-06 12:05:05 +01:00
|
|
|
for (const Frame &f : s.frames()) {
|
2023-08-05 10:33:26 +02:00
|
|
|
qDebug() << f.instructionPointer() << f.directory() << f.fileName() << f.functionName()
|
|
|
|
|
<< f.line() << f.object();
|
2011-03-04 12:15:18 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-05 10:33:26 +02:00
|
|
|
class Recorder : public QObject
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
explicit Recorder(Parser *parser)
|
|
|
|
|
{
|
|
|
|
|
connect(parser, &Parser::error, this, [this](const Error &err) { errors.append(err); });
|
|
|
|
|
connect(parser, &Parser::errorCount, this, [this](qint64 unique, qint64 count) {
|
|
|
|
|
errorcounts.push_back({unique, count});
|
|
|
|
|
});
|
|
|
|
|
connect(parser, &Parser::suppressionCount, this, [this](const QString &name, qint64 count) {
|
|
|
|
|
suppcounts.push_back({name, count});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QList<Error> errors;
|
|
|
|
|
QList<QPair<qint64, qint64>> errorcounts;
|
|
|
|
|
QList<QPair<QString, qint64>> suppcounts;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class RunnerDumper : public QObject
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
explicit RunnerDumper(ValgrindRunner *runner)
|
|
|
|
|
{
|
|
|
|
|
connect(runner, &ValgrindRunner::error, this, [](const Error &err) {
|
|
|
|
|
qDebug() << "error received";
|
|
|
|
|
dumpError(err);
|
|
|
|
|
});
|
|
|
|
|
connect(runner, &ValgrindRunner::internalError, this, [](const QString &err) {
|
|
|
|
|
qDebug() << "internal error received:" << err;
|
|
|
|
|
});
|
|
|
|
|
connect(runner, &ValgrindRunner::status, this, [](const Status &status) {
|
|
|
|
|
qDebug() << "status received:" << status.state() << status.time();
|
|
|
|
|
});
|
|
|
|
|
connect(runner, &ValgrindRunner::logMessageReceived, this, [](const QByteArray &log) {
|
|
|
|
|
qDebug() << "log message received:" << log;
|
|
|
|
|
});
|
|
|
|
|
connect(runner, &ValgrindRunner::processErrorReceived, this, [this](const QString &) {
|
|
|
|
|
m_errorReceived = true;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool m_errorReceived = false;
|
|
|
|
|
};
|
|
|
|
|
|
2011-03-04 12:15:18 +01:00
|
|
|
static QString fakeValgrindExecutable()
|
|
|
|
|
{
|
2023-08-05 10:33:26 +02:00
|
|
|
const QString valgrindFakePath(VALGRIND_FAKE_PATH);
|
|
|
|
|
if (HostOsInfo::isWindowsHost()) {
|
2016-12-06 12:05:05 +01:00
|
|
|
QFileInfo fi(QString(valgrindFakePath + "/debug"), "valgrind-fake.exe");
|
|
|
|
|
if (fi.exists())
|
|
|
|
|
return fi.canonicalFilePath();
|
|
|
|
|
fi = QFileInfo(QString(valgrindFakePath + "/release"), "valgrind-fake.exe");
|
2016-12-19 09:09:46 +01:00
|
|
|
if (fi.exists())
|
|
|
|
|
return fi.canonicalFilePath();
|
|
|
|
|
// Qbs uses the install-root/bin
|
|
|
|
|
fi = QFileInfo(valgrindFakePath, "valgrind-fake.exe");
|
2016-12-06 12:05:05 +01:00
|
|
|
if (fi.exists())
|
|
|
|
|
return fi.canonicalFilePath();
|
|
|
|
|
qFatal("Neither debug nor release build valgrind-fake found.");
|
|
|
|
|
}
|
|
|
|
|
return valgrindFakePath + "/valgrind-fake";
|
2011-03-04 12:15:18 +01:00
|
|
|
}
|
|
|
|
|
|
2017-02-09 14:34:21 +01:00
|
|
|
static QString dataFile(const QString &file)
|
2011-03-04 12:15:18 +01:00
|
|
|
{
|
2017-02-09 14:34:21 +01:00
|
|
|
return QString(PARSERTESTS_DATA_DIR) + '/' + file;
|
2011-03-04 12:15:18 +01:00
|
|
|
}
|
|
|
|
|
|
2016-12-07 08:24:33 +01:00
|
|
|
static QString extraDataFile(const QString &file)
|
|
|
|
|
{
|
2020-09-22 14:51:45 +02:00
|
|
|
// Clone test data from: https://git.qt.io/chstenge/creator-test-data
|
2022-08-24 14:57:57 +02:00
|
|
|
static QString prefix = qtcEnvironmentVariable("QTC_TEST_EXTRADATALOCATION");
|
2016-12-07 08:24:33 +01:00
|
|
|
if (prefix.isEmpty())
|
2023-08-05 14:02:34 +02:00
|
|
|
return {};
|
2016-12-07 08:24:33 +01:00
|
|
|
|
2023-08-05 14:02:34 +02:00
|
|
|
const QFileInfo fi(QString(prefix + "/valgrind"), file);
|
2016-12-07 08:24:33 +01:00
|
|
|
if (fi.exists())
|
|
|
|
|
return fi.canonicalFilePath();
|
2023-08-05 14:02:34 +02:00
|
|
|
return {};
|
2016-12-07 08:24:33 +01:00
|
|
|
}
|
|
|
|
|
|
2016-12-06 12:05:05 +01:00
|
|
|
void ValgrindMemcheckParserTest::initTestCase()
|
2011-03-04 12:15:18 +01:00
|
|
|
{
|
|
|
|
|
m_server = new QTcpServer(this);
|
|
|
|
|
QVERIFY(m_server->listen());
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-09 14:34:21 +01:00
|
|
|
void ValgrindMemcheckParserTest::initTest(const QString &testfile, const QStringList &otherArgs)
|
2011-03-04 12:15:18 +01:00
|
|
|
{
|
|
|
|
|
QVERIFY(!m_server->hasPendingConnections());
|
|
|
|
|
|
2023-08-08 20:50:00 +02:00
|
|
|
m_process.reset(new Process);
|
2011-03-04 12:15:18 +01:00
|
|
|
m_process->setProcessChannelMode(QProcess::ForwardedChannels);
|
2013-09-05 12:29:55 +02:00
|
|
|
const QString fakeValgrind = fakeValgrindExecutable();
|
2023-08-05 14:02:34 +02:00
|
|
|
const QFileInfo fileInfo(fakeValgrind);
|
2013-09-05 12:29:55 +02:00
|
|
|
QVERIFY2(fileInfo.isExecutable(), qPrintable(fakeValgrind));
|
|
|
|
|
QVERIFY2(!fileInfo.isDir(), qPrintable(fakeValgrind));
|
|
|
|
|
|
2023-08-08 20:50:00 +02:00
|
|
|
const QStringList args = {QString("--xml-socket=127.0.0.1:%1").arg(m_server->serverPort()),
|
|
|
|
|
"-i", testfile};
|
|
|
|
|
m_process->setCommand({FilePath::fromString(fakeValgrind), args + otherArgs});
|
|
|
|
|
m_process->start();
|
2011-03-04 12:15:18 +01:00
|
|
|
|
|
|
|
|
QVERIFY(m_process->waitForStarted(5000));
|
|
|
|
|
QCOMPARE(m_process->state(), QProcess::Running);
|
|
|
|
|
QVERIFY2(m_process->error() == QProcess::UnknownError, qPrintable(m_process->errorString()));
|
|
|
|
|
QVERIFY(m_server->waitForNewConnection(5000));
|
2023-08-08 20:05:56 +02:00
|
|
|
m_socket.reset(m_server->nextPendingConnection());
|
2011-03-04 12:15:18 +01:00
|
|
|
QVERIFY(m_socket);
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-06 12:05:05 +01:00
|
|
|
void ValgrindMemcheckParserTest::cleanup()
|
2011-03-04 12:15:18 +01:00
|
|
|
{
|
2023-08-08 20:05:56 +02:00
|
|
|
m_socket.reset();
|
2023-08-08 20:50:00 +02:00
|
|
|
m_process.reset();
|
2011-03-04 12:15:18 +01:00
|
|
|
}
|
|
|
|
|
|
2016-12-06 12:05:05 +01:00
|
|
|
void ValgrindMemcheckParserTest::testHelgrindSample1()
|
2011-03-04 12:15:18 +01:00
|
|
|
{
|
2016-12-07 08:24:33 +01:00
|
|
|
const QString file = extraDataFile("helgrind-output-sample1.xml");
|
|
|
|
|
if (file.isEmpty())
|
|
|
|
|
QSKIP("test file does not exist");
|
2013-02-22 17:07:43 +01:00
|
|
|
|
2016-12-07 08:24:33 +01:00
|
|
|
initTest(file);
|
2011-03-04 12:15:18 +01:00
|
|
|
|
|
|
|
|
QList<Error> expectedErrors;
|
|
|
|
|
{
|
|
|
|
|
Error error1;
|
|
|
|
|
error1.setUnique(0x0);
|
|
|
|
|
error1.setTid(1);
|
|
|
|
|
error1.setKind(LockOrder);
|
2017-02-09 14:34:21 +01:00
|
|
|
error1.setWhat("Thread #1: lock order \"0xA39C270 before 0xA3AC010\" violated");
|
2011-03-04 12:15:18 +01:00
|
|
|
error1.setHelgrindThreadId(1);
|
|
|
|
|
Stack stack1;
|
|
|
|
|
Frame frame11;
|
|
|
|
|
frame11.setInstructionPointer(0x4C2B806);
|
2017-02-09 14:34:21 +01:00
|
|
|
frame11.setObject("/usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so");
|
|
|
|
|
frame11.setFunctionName("QMutex::lock()");
|
|
|
|
|
frame11.setDirectory("/build/buildd/valgrind-3.6.0~svn20100212/helgrind");
|
|
|
|
|
frame11.setFileName("hg_intercepts.c");
|
2011-03-04 12:15:18 +01:00
|
|
|
frame11.setLine(1988);
|
|
|
|
|
Frame frame12;
|
|
|
|
|
frame12.setInstructionPointer(0x72E57EE);
|
2017-02-09 14:34:21 +01:00
|
|
|
frame12.setObject("/home/frank/local/qt4-4.6.3-shared-debug/lib/libQtCore.so.4.6.3");
|
|
|
|
|
frame12.setFunctionName("QMutexLocker::relock()");
|
|
|
|
|
frame12.setDirectory("/home/frank/source/tarballs/qt-4.6.3-build/src/corelib/../../include/QtCore/../../src/corelib/thread");
|
|
|
|
|
frame12.setFileName("qmutex.h");
|
2011-03-04 12:15:18 +01:00
|
|
|
frame12.setLine(120);
|
2023-08-05 14:02:34 +02:00
|
|
|
stack1.setFrames({frame11, frame12});
|
2011-03-04 12:15:18 +01:00
|
|
|
|
|
|
|
|
Stack stack2;
|
2017-02-09 14:34:21 +01:00
|
|
|
stack2.setAuxWhat("Required order was established by acquisition of lock at 0xA39C270");
|
2011-03-04 12:15:18 +01:00
|
|
|
Frame frame21;
|
|
|
|
|
frame21.setInstructionPointer(0x4C2B806);
|
2017-02-09 14:34:21 +01:00
|
|
|
frame21.setObject("/usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so");
|
|
|
|
|
frame21.setFunctionName("QMutex::lock()");
|
|
|
|
|
frame21.setDirectory("/build/buildd/valgrind-3.6.0~svn20100212/helgrind");
|
|
|
|
|
frame21.setFileName("hg_intercepts.c");
|
2011-03-04 12:15:18 +01:00
|
|
|
frame21.setLine(1989);
|
|
|
|
|
Frame frame22;
|
|
|
|
|
frame22.setInstructionPointer(0x72E57EE);
|
2017-02-09 14:34:21 +01:00
|
|
|
frame22.setObject("/home/frank/local/qt4-4.6.3-shared-debug/lib/libQtCore.so.4.6.3");
|
|
|
|
|
frame22.setFunctionName("QMutexLocker::relock()");
|
|
|
|
|
frame22.setDirectory("/home/frank/source/tarballs/qt-4.6.3-build/src/corelib/../../include/QtCore/../../src/corelib/thread");
|
|
|
|
|
frame22.setFileName("qmutex.h");
|
2011-03-04 12:15:18 +01:00
|
|
|
frame22.setLine(121);
|
2023-08-05 14:02:34 +02:00
|
|
|
stack2.setFrames({frame21, frame22});
|
2011-03-04 12:15:18 +01:00
|
|
|
|
|
|
|
|
Stack stack3;
|
2017-02-09 14:34:21 +01:00
|
|
|
stack3.setAuxWhat("followed by a later acquisition of lock at 0xA3AC010");
|
2011-03-04 12:15:18 +01:00
|
|
|
Frame frame31;
|
|
|
|
|
frame31.setInstructionPointer(0x4C2B806);
|
2017-02-09 14:34:21 +01:00
|
|
|
frame31.setObject("/usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so");
|
|
|
|
|
frame31.setFunctionName("QMutex::lock()");
|
|
|
|
|
frame31.setDirectory("/build/buildd/valgrind-3.6.0~svn20100212/helgrind");
|
|
|
|
|
frame31.setFileName("hg_intercepts.c");
|
2011-03-04 12:15:18 +01:00
|
|
|
frame31.setLine(1990);
|
|
|
|
|
Frame frame32;
|
|
|
|
|
frame32.setInstructionPointer(0x72E57EE);
|
2017-02-09 14:34:21 +01:00
|
|
|
frame32.setObject("/home/frank/local/qt4-4.6.3-shared-debug/lib/libQtCore.so.4.6.3");
|
|
|
|
|
frame32.setFunctionName("QMutexLocker::relock()");
|
|
|
|
|
frame32.setDirectory("/home/frank/source/tarballs/qt-4.6.3-build/src/corelib/../../include/QtCore/../../src/corelib/thread");
|
|
|
|
|
frame32.setFileName("qmutex.h");
|
2011-03-04 12:15:18 +01:00
|
|
|
frame32.setLine(122);
|
|
|
|
|
|
2023-08-05 14:02:34 +02:00
|
|
|
stack3.setFrames({frame31, frame32});
|
|
|
|
|
error1.setStacks({stack1, stack2, stack3});
|
2011-03-04 12:15:18 +01:00
|
|
|
expectedErrors.append(error1);
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-03 23:56:02 +02:00
|
|
|
Parser parser;
|
2011-03-04 12:15:18 +01:00
|
|
|
Recorder rec(&parser);
|
|
|
|
|
|
2023-08-09 12:40:40 +02:00
|
|
|
parser.setSocket(m_socket.release());
|
|
|
|
|
parser.runBlocking();
|
2011-03-04 12:15:18 +01:00
|
|
|
|
|
|
|
|
m_process->waitForFinished();
|
|
|
|
|
QCOMPARE(m_process->exitStatus(), QProcess::NormalExit);
|
|
|
|
|
QCOMPARE(m_process->state(), QProcess::NotRunning);
|
|
|
|
|
|
|
|
|
|
QVERIFY2(parser.errorString().isEmpty(), qPrintable(parser.errorString()));
|
|
|
|
|
const QList<Error> actualErrors = rec.errors;
|
2023-08-09 12:40:40 +02:00
|
|
|
QVERIFY(!actualErrors.isEmpty());
|
2011-03-04 12:15:18 +01:00
|
|
|
if (actualErrors.first() != expectedErrors.first()) {
|
|
|
|
|
dumpError(actualErrors.first());
|
|
|
|
|
dumpError(expectedErrors.first());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QCOMPARE(actualErrors.first(), expectedErrors.first());
|
|
|
|
|
|
|
|
|
|
QCOMPARE(actualErrors.size(), 1);
|
|
|
|
|
|
|
|
|
|
// QCOMPARE(rec.errorcounts, expectedErrorCounts);
|
|
|
|
|
// QCOMPARE(rec.suppcounts, expectedSuppCounts);
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-06 12:05:05 +01:00
|
|
|
void ValgrindMemcheckParserTest::testMemcheckSample1()
|
2011-03-04 12:15:18 +01:00
|
|
|
{
|
2016-12-07 08:24:33 +01:00
|
|
|
initTest(dataFile("memcheck-output-sample1.xml"));
|
2011-03-04 12:15:18 +01:00
|
|
|
|
|
|
|
|
QList<Error> expectedErrors;
|
|
|
|
|
{
|
|
|
|
|
Error error;
|
|
|
|
|
error.setKind(InvalidRead);
|
2017-02-09 14:34:21 +01:00
|
|
|
error.setWhat("Invalid read of size 4");
|
2011-03-04 12:15:18 +01:00
|
|
|
error.setUnique(0x9);
|
|
|
|
|
error.setTid(1);
|
|
|
|
|
Frame f1;
|
|
|
|
|
f1.setInstructionPointer(0x6E47964);
|
2017-02-09 14:34:21 +01:00
|
|
|
f1.setObject("/usr/lib/libQtGui.so.4.7.0");
|
|
|
|
|
f1.setFunctionName("QFrame::frameStyle() const");
|
|
|
|
|
f1.setDirectory("/build/buildd/qt4-x11-4.7.0/src/gui/widgets");
|
|
|
|
|
f1.setFileName("qframe.cpp");
|
2011-03-04 12:15:18 +01:00
|
|
|
f1.setLine(252);
|
|
|
|
|
Frame f2;
|
|
|
|
|
f2.setInstructionPointer(0x118F2AF7);
|
2017-02-09 14:34:21 +01:00
|
|
|
f2.setObject("/usr/lib/kde4/plugins/styles/oxygen.so");
|
2011-03-04 12:15:18 +01:00
|
|
|
Frame f3;
|
|
|
|
|
f3.setInstructionPointer(0x6A81671);
|
2017-02-09 14:34:21 +01:00
|
|
|
f3.setObject("/usr/lib/libQtGui.so.4.7.0");
|
|
|
|
|
f3.setFunctionName("QWidget::event(QEvent*)");
|
|
|
|
|
f3.setDirectory("/build/buildd/qt4-x11-4.7.0/src/gui/kernel");
|
|
|
|
|
f3.setFileName("qwidget.cpp");
|
2011-03-04 12:15:18 +01:00
|
|
|
f3.setLine(8273);
|
|
|
|
|
Frame f4;
|
|
|
|
|
f4.setInstructionPointer(0x6A2B6EB);
|
2017-02-09 14:34:21 +01:00
|
|
|
f4.setObject("/usr/lib/libQtGui.so.4.7.0");
|
|
|
|
|
f4.setDirectory("/build/buildd/qt4-x11-4.7.0/src/gui/kernel");
|
|
|
|
|
f4.setFileName("qapplication.cpp");
|
|
|
|
|
f4.setFunctionName("QApplicationPrivate::notify_helper(QObject*, QEvent*)");
|
2011-03-04 12:15:18 +01:00
|
|
|
f4.setLine(4396);
|
|
|
|
|
Stack s1;
|
2017-02-09 14:34:21 +01:00
|
|
|
s1.setAuxWhat("Address 0x11527cb8 is not stack'd, malloc'd or (recently) free'd");
|
2023-08-05 14:02:34 +02:00
|
|
|
s1.setFrames({f1, f2, f3, f4});
|
|
|
|
|
error.setStacks({s1});
|
2011-03-04 12:15:18 +01:00
|
|
|
|
|
|
|
|
expectedErrors << error;
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-05 10:55:52 +02:00
|
|
|
const QList<QPair<qint64, qint64>> expectedErrorCounts{{9, 2}};
|
|
|
|
|
const QList<QPair<QString, qint64>> expectedSuppCounts{
|
2022-09-30 11:12:51 +02:00
|
|
|
{QString("X on SUSE11 writev uninit padding"), 12},
|
|
|
|
|
{QString("dl-hack3-cond-1"), 2},
|
|
|
|
|
{QString("glibc-2.5.x-on-SUSE-10.2-(PPC)-2a"), 2}};
|
2011-03-04 12:15:18 +01:00
|
|
|
|
2015-02-03 23:56:02 +02:00
|
|
|
Parser parser;
|
2011-03-04 12:15:18 +01:00
|
|
|
Recorder rec(&parser);
|
|
|
|
|
|
2023-08-09 12:40:40 +02:00
|
|
|
parser.setSocket(m_socket.release());
|
|
|
|
|
parser.runBlocking();
|
2011-03-04 12:15:18 +01:00
|
|
|
|
|
|
|
|
m_process->waitForFinished();
|
|
|
|
|
QCOMPARE(m_process->exitStatus(), QProcess::NormalExit);
|
|
|
|
|
QCOMPARE(m_process->state(), QProcess::NotRunning);
|
|
|
|
|
|
|
|
|
|
QVERIFY2(parser.errorString().isEmpty(), qPrintable(parser.errorString()));
|
|
|
|
|
const QList<Error> actualErrors = rec.errors;
|
2023-08-09 12:40:40 +02:00
|
|
|
QVERIFY(!actualErrors.isEmpty());
|
2011-03-04 12:15:18 +01:00
|
|
|
if (actualErrors.first() != expectedErrors.first()) {
|
|
|
|
|
dumpError(actualErrors.first());
|
|
|
|
|
dumpError(expectedErrors.first());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QCOMPARE(actualErrors.first(), expectedErrors.first());
|
|
|
|
|
|
|
|
|
|
QCOMPARE(actualErrors.size(), 3);
|
|
|
|
|
|
|
|
|
|
QCOMPARE(rec.errorcounts, expectedErrorCounts);
|
|
|
|
|
QCOMPARE(rec.suppcounts, expectedSuppCounts);
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-06 12:05:05 +01:00
|
|
|
void ValgrindMemcheckParserTest::testMemcheckSample2()
|
2011-03-04 12:15:18 +01:00
|
|
|
{
|
2016-12-07 08:24:33 +01:00
|
|
|
const QString file = extraDataFile("memcheck-output-sample2.xml");
|
|
|
|
|
if (file.isEmpty())
|
|
|
|
|
QSKIP("test file does not exist");
|
2013-02-22 17:07:43 +01:00
|
|
|
|
2016-12-07 08:24:33 +01:00
|
|
|
initTest(file);
|
2011-03-04 12:15:18 +01:00
|
|
|
|
2015-02-03 23:56:02 +02:00
|
|
|
Parser parser;
|
2011-03-04 12:15:18 +01:00
|
|
|
Recorder rec(&parser);
|
|
|
|
|
|
2023-08-09 12:40:40 +02:00
|
|
|
parser.setSocket(m_socket.release());
|
|
|
|
|
parser.runBlocking();
|
2011-03-04 12:15:18 +01:00
|
|
|
|
|
|
|
|
m_process->waitForFinished();
|
|
|
|
|
QCOMPARE(m_process->exitStatus(), QProcess::NormalExit);
|
|
|
|
|
QCOMPARE(m_process->state(), QProcess::NotRunning);
|
|
|
|
|
QVERIFY2(parser.errorString().isEmpty(), qPrintable(parser.errorString()));
|
|
|
|
|
|
|
|
|
|
//tests: multiple stacks with auxwhat == stack count - 1.
|
|
|
|
|
//the first auxwhat should be assigned to the _second_ stack.
|
|
|
|
|
const QList<Error> errors = rec.errors;
|
|
|
|
|
QCOMPARE(errors.size(), 1);
|
2023-08-05 10:55:52 +02:00
|
|
|
const QList<Stack> stacks = errors.first().stacks();
|
2011-03-04 12:15:18 +01:00
|
|
|
QCOMPARE(stacks.size(), 2);
|
|
|
|
|
QCOMPARE(stacks.first().auxWhat(), QString());
|
2017-02-09 14:34:21 +01:00
|
|
|
QCOMPARE(stacks.last().auxWhat(), "Address 0x11b66c50 is 0 bytes inside a block of size 16 free'd");
|
2011-03-04 12:15:18 +01:00
|
|
|
}
|
|
|
|
|
|
2016-12-06 12:05:05 +01:00
|
|
|
void ValgrindMemcheckParserTest::testMemcheckSample3()
|
2011-03-04 12:15:18 +01:00
|
|
|
{
|
2016-12-07 08:24:33 +01:00
|
|
|
const QString file = extraDataFile("memcheck-output-sample3.xml");
|
|
|
|
|
if (file.isEmpty())
|
|
|
|
|
QSKIP("test file does not exist");
|
2013-02-22 17:07:43 +01:00
|
|
|
|
2016-12-07 08:24:33 +01:00
|
|
|
initTest(file);
|
2011-03-04 12:15:18 +01:00
|
|
|
|
2015-02-03 23:56:02 +02:00
|
|
|
Parser parser;
|
2011-03-04 12:15:18 +01:00
|
|
|
Recorder rec(&parser);
|
|
|
|
|
|
2023-08-09 12:40:40 +02:00
|
|
|
parser.setSocket(m_socket.release());
|
|
|
|
|
parser.runBlocking();
|
2011-03-04 12:15:18 +01:00
|
|
|
|
|
|
|
|
m_process->waitForFinished();
|
|
|
|
|
QCOMPARE(m_process->exitStatus(), QProcess::NormalExit);
|
|
|
|
|
QCOMPARE(m_process->state(), QProcess::NotRunning);
|
|
|
|
|
QVERIFY2(parser.errorString().isEmpty(), qPrintable(parser.errorString()));
|
|
|
|
|
|
|
|
|
|
const QList<Error> errors = rec.errors;
|
|
|
|
|
QCOMPARE(errors.size(), 6);
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
const Error error = errors.at(0);
|
2023-08-05 10:55:52 +02:00
|
|
|
const QList<Stack> stacks = error.stacks();
|
2011-03-04 12:15:18 +01:00
|
|
|
|
|
|
|
|
QCOMPARE(error.unique(), 0x1ll);
|
2017-02-09 14:34:21 +01:00
|
|
|
QCOMPARE(error.what(), "Conditional jump or move depends on uninitialised value(s)");
|
2011-03-04 12:15:18 +01:00
|
|
|
QCOMPARE(error.kind(), UninitCondition);
|
|
|
|
|
QCOMPARE(stacks.size(), 1);
|
|
|
|
|
QCOMPARE(stacks.first().frames().size(), 12);
|
|
|
|
|
QVERIFY(!error.suppression().isNull());
|
|
|
|
|
QCOMPARE(error.suppression().frames().count(), stacks.first().frames().size());
|
2017-02-09 14:34:21 +01:00
|
|
|
QCOMPARE(error.suppression().kind(), "Memcheck:Cond");
|
2011-03-04 12:15:18 +01:00
|
|
|
QVERIFY(!error.suppression().rawText().trimmed().isEmpty());
|
|
|
|
|
|
|
|
|
|
// rawtext contains <...> while <name></name> does not
|
2017-02-09 14:34:21 +01:00
|
|
|
QCOMPARE(error.suppression().name(), "insert_a_suppression_name_here");
|
2011-03-04 12:15:18 +01:00
|
|
|
Suppression sup = error.suppression();
|
2017-02-09 14:34:21 +01:00
|
|
|
sup.setName("<insert_a_suppression_name_here>");
|
2011-03-04 12:15:18 +01:00
|
|
|
QCOMPARE(sup.toString().trimmed(), sup.rawText().trimmed());
|
|
|
|
|
|
|
|
|
|
QCOMPARE(error.suppression().frames().first().object(),
|
2017-02-09 14:34:21 +01:00
|
|
|
"/usr/lib/kde4/plugins/styles/qtcurve.so");
|
2011-03-04 12:15:18 +01:00
|
|
|
QVERIFY(error.suppression().frames().first().function().isEmpty());
|
2017-02-09 14:34:21 +01:00
|
|
|
QCOMPARE(error.suppression().frames().last().function(), "main");
|
2011-03-04 12:15:18 +01:00
|
|
|
QVERIFY(error.suppression().frames().last().object().isEmpty());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QCOMPARE(rec.suppcounts.count(), 3);
|
|
|
|
|
QCOMPARE(rec.suppcounts.at(0).second, qint64(1));
|
|
|
|
|
QCOMPARE(rec.suppcounts.at(1).second, qint64(2));
|
|
|
|
|
QCOMPARE(rec.suppcounts.at(2).second, qint64(3));
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-06 12:05:05 +01:00
|
|
|
void ValgrindMemcheckParserTest::testMemcheckCharm()
|
2011-03-04 12:15:18 +01:00
|
|
|
{
|
|
|
|
|
// a somewhat larger file, to make sure buffering and partial I/O works ok
|
2016-12-07 08:24:33 +01:00
|
|
|
const QString file = extraDataFile("memcheck-output-charm.xml");
|
|
|
|
|
if (file.isEmpty())
|
|
|
|
|
QSKIP("test file does not exist");
|
|
|
|
|
|
|
|
|
|
initTest(file);
|
2011-03-04 12:15:18 +01:00
|
|
|
|
2015-02-03 23:56:02 +02:00
|
|
|
Parser parser;
|
2011-03-04 12:15:18 +01:00
|
|
|
Recorder rec(&parser);
|
|
|
|
|
|
2023-08-09 12:40:40 +02:00
|
|
|
parser.setSocket(m_socket.release());
|
|
|
|
|
parser.runBlocking();
|
2011-03-04 12:15:18 +01:00
|
|
|
|
|
|
|
|
m_process->waitForFinished();
|
|
|
|
|
QCOMPARE(m_process->exitStatus(), QProcess::NormalExit);
|
|
|
|
|
QCOMPARE(m_process->state(), QProcess::NotRunning);
|
|
|
|
|
|
|
|
|
|
const QList<Error> errors = rec.errors;
|
|
|
|
|
QCOMPARE(errors.size(), 102);
|
|
|
|
|
QVERIFY2(parser.errorString().isEmpty(), qPrintable(parser.errorString()));
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-06 12:05:05 +01:00
|
|
|
void ValgrindMemcheckParserTest::testValgrindCrash()
|
2011-03-04 12:15:18 +01:00
|
|
|
{
|
2016-12-07 08:24:33 +01:00
|
|
|
initTest(dataFile("memcheck-output-sample1.xml"), QStringList("--crash"));
|
2011-03-04 12:15:18 +01:00
|
|
|
|
2015-02-03 23:56:02 +02:00
|
|
|
Parser parser;
|
2023-08-09 12:40:40 +02:00
|
|
|
parser.setSocket(m_socket.release());
|
|
|
|
|
parser.runBlocking();
|
2011-03-04 12:15:18 +01:00
|
|
|
m_process->waitForFinished();
|
|
|
|
|
QCOMPARE(m_process->state(), QProcess::NotRunning);
|
|
|
|
|
QCOMPARE(m_process->exitStatus(), QProcess::CrashExit);
|
|
|
|
|
|
|
|
|
|
QVERIFY(!parser.errorString().isEmpty());
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-06 12:05:05 +01:00
|
|
|
void ValgrindMemcheckParserTest::testValgrindGarbage()
|
2011-03-04 12:15:18 +01:00
|
|
|
{
|
2016-12-07 08:24:33 +01:00
|
|
|
initTest(dataFile("memcheck-output-sample1.xml"), QStringList("--garbage"));
|
2011-03-04 12:15:18 +01:00
|
|
|
|
2015-02-03 23:56:02 +02:00
|
|
|
Parser parser;
|
2023-08-09 12:40:40 +02:00
|
|
|
parser.setSocket(m_socket.release());
|
|
|
|
|
parser.runBlocking();
|
2011-03-04 12:15:18 +01:00
|
|
|
m_process->waitForFinished();
|
|
|
|
|
QCOMPARE(m_process->state(), QProcess::NotRunning);
|
|
|
|
|
QCOMPARE(m_process->exitStatus(), QProcess::NormalExit);
|
|
|
|
|
|
|
|
|
|
QVERIFY(!parser.errorString().isEmpty());
|
|
|
|
|
qDebug() << parser.errorString();
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-06 12:05:05 +01:00
|
|
|
void ValgrindMemcheckParserTest::testParserStop()
|
2011-03-04 12:15:18 +01:00
|
|
|
{
|
2017-06-21 08:08:43 +02:00
|
|
|
ValgrindRunner runner;
|
2021-08-10 16:19:02 +02:00
|
|
|
runner.setValgrindCommand({FilePath::fromString(fakeValgrindExecutable()),
|
2019-07-23 08:30:25 +02:00
|
|
|
{QString("--xml-socket=127.0.0.1:%1").arg(m_server->serverPort()),
|
|
|
|
|
"-i", dataFile("memcheck-output-sample1.xml"), "--wait", "5" }});
|
2011-03-04 12:15:18 +01:00
|
|
|
runner.setProcessChannelMode(QProcess::ForwardedChannels);
|
|
|
|
|
|
|
|
|
|
runner.start();
|
|
|
|
|
QTest::qWait(500);
|
|
|
|
|
runner.stop();
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-06 12:05:05 +01:00
|
|
|
void ValgrindMemcheckParserTest::testRealValgrind()
|
2011-03-04 12:15:18 +01:00
|
|
|
{
|
2023-08-05 10:33:26 +02:00
|
|
|
const Environment &sysEnv = Environment::systemEnvironment();
|
2023-08-05 14:02:34 +02:00
|
|
|
const auto fileName = sysEnv.searchInPath("valgrind");
|
2016-12-06 12:05:05 +01:00
|
|
|
if (fileName.isEmpty())
|
|
|
|
|
QSKIP("This test needs valgrind in PATH");
|
2023-08-05 14:02:34 +02:00
|
|
|
QString executable = QProcessEnvironment::systemEnvironment().value("VALGRIND_TEST_BIN",
|
|
|
|
|
fakeValgrindExecutable());
|
2011-03-04 12:15:18 +01:00
|
|
|
qDebug() << "running exe:" << executable << " HINT: set VALGRIND_TEST_BIN to change this";
|
|
|
|
|
|
2018-05-16 15:42:03 +02:00
|
|
|
ProjectExplorer::Runnable debuggee;
|
2021-08-10 09:19:30 +02:00
|
|
|
debuggee.command.setExecutable(FilePath::fromString(executable));
|
2016-12-06 12:05:05 +01:00
|
|
|
debuggee.environment = sysEnv;
|
2017-06-21 08:08:43 +02:00
|
|
|
ValgrindRunner runner;
|
2019-07-23 10:17:57 +02:00
|
|
|
runner.setValgrindCommand({"valgrind", {}});
|
2016-01-26 16:11:39 +01:00
|
|
|
runner.setDebuggee(debuggee);
|
2017-06-21 09:01:48 +02:00
|
|
|
RunnerDumper dumper(&runner);
|
2023-08-16 16:41:44 +02:00
|
|
|
runner.runBlocking();
|
2011-03-04 12:15:18 +01:00
|
|
|
}
|
|
|
|
|
|
2016-12-06 12:05:05 +01:00
|
|
|
void ValgrindMemcheckParserTest::testValgrindStartError_data()
|
2011-03-04 12:15:18 +01:00
|
|
|
{
|
|
|
|
|
QTest::addColumn<QString>("valgrindExe");
|
|
|
|
|
QTest::addColumn<QStringList>("valgrindArgs");
|
|
|
|
|
QTest::addColumn<QString>("debuggee");
|
|
|
|
|
QTest::addColumn<QString>("debuggeeArgs");
|
|
|
|
|
|
2017-02-09 14:34:21 +01:00
|
|
|
QTest::newRow("invalid_client") << "valgrind" << QStringList()
|
|
|
|
|
<< "please-dont-let-this-app-exist" << QString();
|
2011-03-04 12:15:18 +01:00
|
|
|
|
2017-02-09 14:34:21 +01:00
|
|
|
QTest::newRow("invalid_valgrind") << "valgrind-that-does-not-exist" << QStringList()
|
|
|
|
|
<< fakeValgrindExecutable() << QString();
|
2011-03-04 12:15:18 +01:00
|
|
|
|
2017-02-09 14:34:21 +01:00
|
|
|
QTest::newRow("invalid_valgrind_args") << "valgrind" << QStringList("--foobar-fail")
|
2011-03-04 12:15:18 +01:00
|
|
|
<< fakeValgrindExecutable() << QString();
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-06 12:05:05 +01:00
|
|
|
void ValgrindMemcheckParserTest::testValgrindStartError()
|
2011-03-04 12:15:18 +01:00
|
|
|
{
|
|
|
|
|
QFETCH(QString, valgrindExe);
|
|
|
|
|
QFETCH(QStringList, valgrindArgs);
|
2016-12-06 12:05:05 +01:00
|
|
|
QFETCH(QString, debuggee);
|
2011-03-04 12:15:18 +01:00
|
|
|
QFETCH(QString, debuggeeArgs);
|
|
|
|
|
|
2018-05-16 15:42:03 +02:00
|
|
|
ProjectExplorer::Runnable debuggeeExecutable;
|
2021-08-10 09:19:30 +02:00
|
|
|
debuggeeExecutable.command.setExecutable(FilePath::fromString(debuggee));
|
|
|
|
|
debuggeeExecutable.command.setArguments(debuggeeArgs);
|
2023-08-05 10:33:26 +02:00
|
|
|
debuggeeExecutable.environment = Environment::systemEnvironment();
|
2016-01-26 16:11:39 +01:00
|
|
|
|
2017-06-21 08:08:43 +02:00
|
|
|
ValgrindRunner runner;
|
2021-08-10 16:19:02 +02:00
|
|
|
runner.setValgrindCommand({FilePath::fromString(valgrindExe), valgrindArgs});
|
2016-12-06 12:05:05 +01:00
|
|
|
runner.setDebuggee(debuggeeExecutable);
|
2017-06-21 09:01:48 +02:00
|
|
|
RunnerDumper dumper(&runner);
|
2023-08-16 16:41:44 +02:00
|
|
|
runner.runBlocking();
|
2011-03-04 12:15:18 +01:00
|
|
|
QVERIFY(dumper.m_errorReceived);
|
|
|
|
|
// just finish without deadlock and we are fine
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-05 10:33:26 +02:00
|
|
|
} // namespace Valgrind::Test
|