summaryrefslogtreecommitdiff
path: root/tests/valgrind
diff options
context:
space:
mode:
authorMike McQuaid <mike@mikemcquaid.com>2011-03-04 12:15:18 +0100
committerhjk <qtc-committer@nokia.com>2011-03-04 12:33:30 +0100
commit3b703588faacbf4ff2e963f6cb6839ece94a90b3 (patch)
treece61496db5f16a9c37d224dbfd3a8e555fb43d41 /tests/valgrind
parentbbd60cacda707c17c6f3b9c4e4b390ad85743a92 (diff)
downloadqt-creator-3b703588faacbf4ff2e963f6cb6839ece94a90b3.tar.gz
Add libvalgrind tests.
Merge-request: 260 Reviewed-by: hjk <qtc-committer@nokia.com>
Diffstat (limited to 'tests/valgrind')
-rw-r--r--tests/valgrind/README6
-rw-r--r--tests/valgrind/memcheck/memcheck.pro3
-rw-r--r--tests/valgrind/memcheck/modeldemo.cpp99
-rw-r--r--tests/valgrind/memcheck/modeldemo.h80
-rw-r--r--tests/valgrind/memcheck/modeldemo.pro17
-rw-r--r--tests/valgrind/memcheck/parsertests.cpp508
-rw-r--r--tests/valgrind/memcheck/parsertests.h186
-rw-r--r--tests/valgrind/memcheck/parsertests.pro19
-rw-r--r--tests/valgrind/memcheck/testapps/free1/free1.pro8
-rw-r--r--tests/valgrind/memcheck/testapps/free1/main.cpp9
-rw-r--r--tests/valgrind/memcheck/testapps/free2/free2.pro8
-rw-r--r--tests/valgrind/memcheck/testapps/free2/main.cpp8
-rw-r--r--tests/valgrind/memcheck/testapps/invalidjump/invalidjump.pro8
-rw-r--r--tests/valgrind/memcheck/testapps/invalidjump/main.cpp8
-rw-r--r--tests/valgrind/memcheck/testapps/leak1/leak1.pro8
-rw-r--r--tests/valgrind/memcheck/testapps/leak1/main.cpp7
-rw-r--r--tests/valgrind/memcheck/testapps/leak2/leak2.pro8
-rw-r--r--tests/valgrind/memcheck/testapps/leak2/main.cpp13
-rw-r--r--tests/valgrind/memcheck/testapps/leak3/leak3.pro8
-rw-r--r--tests/valgrind/memcheck/testapps/leak3/main.cpp10
-rw-r--r--tests/valgrind/memcheck/testapps/leak4/leak4.pro8
-rw-r--r--tests/valgrind/memcheck/testapps/leak4/main.cpp17
-rw-r--r--tests/valgrind/memcheck/testapps/overlap/main.cpp9
-rw-r--r--tests/valgrind/memcheck/testapps/overlap/overlap.pro8
-rw-r--r--tests/valgrind/memcheck/testapps/syscall/main.cpp5
-rw-r--r--tests/valgrind/memcheck/testapps/syscall/syscall.pro8
-rw-r--r--tests/valgrind/memcheck/testapps/testapps.pro4
-rw-r--r--tests/valgrind/memcheck/testapps/uninit1/main.cpp9
-rw-r--r--tests/valgrind/memcheck/testapps/uninit1/uninit1.pro8
-rw-r--r--tests/valgrind/memcheck/testapps/uninit2/main.cpp7
-rw-r--r--tests/valgrind/memcheck/testapps/uninit2/uninit2.pro8
-rw-r--r--tests/valgrind/memcheck/testapps/uninit3/main.cpp5
-rw-r--r--tests/valgrind/memcheck/testapps/uninit3/uninit3.pro8
-rw-r--r--tests/valgrind/memcheck/testrunner.cpp703
-rw-r--r--tests/valgrind/memcheck/testrunner.h98
-rw-r--r--tests/valgrind/memcheck/testrunner.pro18
-rw-r--r--tests/valgrind/valgrind.pro3
37 files changed, 1947 insertions, 0 deletions
diff --git a/tests/valgrind/README b/tests/valgrind/README
new file mode 100644
index 0000000000..66f9bd24bb
--- /dev/null
+++ b/tests/valgrind/README
@@ -0,0 +1,6 @@
+# How to Compile
+
+cd qtc-build # go to your build folder of qtc
+mkdir valgrind-test
+cd valgrind-test
+qmake CONFIG+=debug IDE_BUILD_TREE=$(readlink -f ..) ../../path/to/qtc/tests/valgrind
diff --git a/tests/valgrind/memcheck/memcheck.pro b/tests/valgrind/memcheck/memcheck.pro
new file mode 100644
index 0000000000..ee72ee0010
--- /dev/null
+++ b/tests/valgrind/memcheck/memcheck.pro
@@ -0,0 +1,3 @@
+TEMPLATE = subdirs
+
+SUBDIRS += parsertests.pro modeldemo.pro testapps testrunner.pro
diff --git a/tests/valgrind/memcheck/modeldemo.cpp b/tests/valgrind/memcheck/modeldemo.cpp
new file mode 100644
index 0000000000..17c54a4c1f
--- /dev/null
+++ b/tests/valgrind/memcheck/modeldemo.cpp
@@ -0,0 +1,99 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Author: Frank Osterfeld, KDAB (frank.osterfeld@kdab.com)
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** No Commercial Usage
+**
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**************************************************************************/
+
+#include <valgrind/xmlprotocol/frame.h>
+#include <valgrind/xmlprotocol/parser.h>
+#include <valgrind/xmlprotocol/stack.h>
+#include <valgrind/xmlprotocol/status.h>
+#include <valgrind/xmlprotocol/threadedparser.h>
+
+#include "modeldemo.h"
+
+#include <QtGui/QApplication>
+#include <QtGui/QTreeView>
+
+using namespace Valgrind;
+using namespace Valgrind::XmlProtocol;
+
+static QString fakeValgrindExecutable()
+{
+ return QCoreApplication::applicationDirPath() + QLatin1String("/../../valgrind-fake/valgrind-fake");
+}
+
+static QString dataFile(const QLatin1String &file)
+{
+ return QLatin1String(PARSERTESTS_DATA_DIR) + QLatin1String("/") + file;
+}
+
+int main(int argc, char *argv[])
+{
+ QApplication app(argc, argv);
+ qRegisterMetaType<Valgrind::XmlProtocol::Error>();
+
+ ThreadedParser parser;
+
+ Valgrind::Memcheck::MemcheckRunner runner;
+ runner.setValgrindExecutable(fakeValgrindExecutable());
+ runner.setValgrindArguments(QStringList() << QLatin1String("-i") << dataFile(QLatin1String("memcheck-output-sample1.xml")) );
+ runner.setParser(&parser);
+
+ ModelDemo demo(&runner);
+ runner.connect(&runner, SIGNAL(finished()), &demo, SLOT(finished()));
+ ErrorListModel model;
+ parser.connect(&parser, SIGNAL(error(Valgrind::XmlProtocol::Error)),
+ &model, SLOT(addError(Valgrind::XmlProtocol::Error)),
+ Qt::QueuedConnection);
+
+ QTreeView errorview;
+ errorview.setSelectionMode(QAbstractItemView::SingleSelection);
+ errorview.setSelectionBehavior(QAbstractItemView::SelectRows);
+ errorview.setModel(&model);
+ errorview.show();
+
+ StackModel stackModel;
+ demo.stackModel = &stackModel;
+
+ QTreeView stackView;
+ stackView.setModel(&stackModel);
+ stackView.show();
+
+ errorview.connect(errorview.selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
+ &demo, SLOT(selectionChanged(QItemSelection,QItemSelection)));
+
+
+ runner.start();
+
+ return app.exec();
+}
diff --git a/tests/valgrind/memcheck/modeldemo.h b/tests/valgrind/memcheck/modeldemo.h
new file mode 100644
index 0000000000..fdc8c03c2f
--- /dev/null
+++ b/tests/valgrind/memcheck/modeldemo.h
@@ -0,0 +1,80 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Author: Frank Osterfeld, KDAB (frank.osterfeld@kdab.com)
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** No Commercial Usage
+**
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**************************************************************************/
+
+#ifndef MODELDEMO_H
+#define MODELDEMO_H
+
+#include <QObject>
+#include <QDebug>
+#include <QItemSelection>
+#include <QModelIndex>
+
+#include <valgrind/xmlprotocol/error.h>
+#include <valgrind/xmlprotocol/errorlistmodel.h>
+#include <valgrind/xmlprotocol/stackmodel.h>
+#include <valgrind/memcheck/memcheckrunner.h>
+
+class ModelDemo : public QObject
+{
+ Q_OBJECT
+public:
+ explicit ModelDemo(Valgrind::Memcheck::MemcheckRunner *r, QObject *parent = 0)
+ : QObject(parent)
+ , runner(r)
+ {
+ }
+
+ Valgrind::XmlProtocol::StackModel* stackModel;
+
+public Q_SLOTS:
+ void finished() {
+ qDebug() << runner->errorString();
+ }
+
+ void selectionChanged(const QItemSelection &sel, const QItemSelection &) {
+ if (sel.indexes().isEmpty())
+ return;
+ const QModelIndex idx = sel.indexes().first();
+ const Valgrind::XmlProtocol::Error err = idx.data(Valgrind::XmlProtocol::ErrorListModel::ErrorRole).value<Valgrind::XmlProtocol::Error>();
+ qDebug() << idx.row() << err.what();
+ stackModel->setError(err);
+ }
+
+
+private:
+ Valgrind::Memcheck::MemcheckRunner *runner;
+};
+
+#endif // MODELDEMO_H
diff --git a/tests/valgrind/memcheck/modeldemo.pro b/tests/valgrind/memcheck/modeldemo.pro
new file mode 100644
index 0000000000..a0a9773c42
--- /dev/null
+++ b/tests/valgrind/memcheck/modeldemo.pro
@@ -0,0 +1,17 @@
+TEMPLATE = app
+TARGET = modeldemo
+
+macx:CONFIG -= app_bundle
+
+QT += gui network
+
+DEFINES += "PARSERTESTS_DATA_DIR=\"\\\"$$PWD/data\\\"\""
+
+!win32 {
+ include(../../../qtcreator.pri)
+ include(../../../src/libs/valgrind/valgrind.pri)
+}
+
+SOURCES += modeldemo.cpp
+
+HEADERS += modeldemo.h
diff --git a/tests/valgrind/memcheck/parsertests.cpp b/tests/valgrind/memcheck/parsertests.cpp
new file mode 100644
index 0000000000..5d1b38e6c3
--- /dev/null
+++ b/tests/valgrind/memcheck/parsertests.cpp
@@ -0,0 +1,508 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator Analyzer Tools
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Author: Frank Osterfeld, KDAB (frank.osterfeld@kdab.com)
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include <valgrind/xmlprotocol/frame.h>
+#include <valgrind/xmlprotocol/parser.h>
+#include <valgrind/xmlprotocol/stack.h>
+#include <valgrind/xmlprotocol/suppression.h>
+
+#include "parsertests.h"
+
+#include <QCoreApplication>
+#include <QDebug>
+#include <QFile>
+#include <QFileInfo>
+#include <QString>
+#include <QTest>
+#include <QTcpServer>
+#include <QTcpSocket>
+#include <QSignalSpy>
+
+#include <iostream>
+#include <QProcess>
+
+using namespace Valgrind;
+using namespace Valgrind::XmlProtocol;
+
+QT_BEGIN_NAMESPACE
+namespace QTest {
+
+template<>
+inline bool qCompare(int const &t1, Valgrind::XmlProtocol::MemcheckErrorKind const &t2,
+ char const *actual, char const *expected, char const *file, int line)
+{
+ return qCompare(t1, int(t2), actual, expected, file, line);
+}
+
+} // namespace QTest
+QT_END_NAMESPACE
+
+void dumpFrame(const Frame &f)
+{
+ qDebug() << f.instructionPointer() << f.directory() << f.file() << f.functionName()
+ << f.line() << f.object();
+}
+
+void dumpError(const Error &e)
+{
+ qDebug() << e.kind() << e.leakedBlocks() << e.leakedBytes() << e.what() << e.tid() << e.unique();
+ qDebug() << "stacks:" << e.stacks().size();
+ Q_FOREACH(const Stack& s, e.stacks()) {
+ qDebug() << s.auxWhat() << s.directory() << s.file() << s.line() << s.helgrindThreadId();
+ qDebug() << "frames:";
+ Q_FOREACH(const Frame& f, s.frames()) {
+ dumpFrame(f);
+ }
+ }
+}
+
+static QString fakeValgrindExecutable()
+{
+ QString ret(VALGRIND_FAKE_PATH);
+ QFileInfo fileInfo(ret);
+ Q_ASSERT(fileInfo.isExecutable());
+ Q_ASSERT(!fileInfo.isDir());
+ return ret;
+}
+
+static QString dataFile(const QLatin1String &file)
+{
+ return QLatin1String(PARSERTESTS_DATA_DIR) + QLatin1String("/") + file;
+}
+
+void ParserTests::initTestCase()
+{
+ m_server = new QTcpServer(this);
+ QVERIFY(m_server->listen());
+
+ m_socket = 0;
+ m_process = 0;
+}
+
+void ParserTests::initTest(const QLatin1String &testfile, const QStringList &otherArgs)
+{
+ QVERIFY(!m_server->hasPendingConnections());
+
+ m_process = new QProcess(m_server);
+ m_process->setProcessChannelMode(QProcess::ForwardedChannels);
+ m_process->start(
+ fakeValgrindExecutable(),
+ QStringList()
+ << QString("--xml-socket=127.0.0.1:%1").arg(m_server->serverPort())
+ << QLatin1String("-i")
+ << dataFile(testfile)
+ << otherArgs
+ );
+
+ 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));
+ m_socket = m_server->nextPendingConnection();
+ QVERIFY(m_socket);
+}
+
+void ParserTests::cleanup()
+{
+ if (m_socket) {
+ delete m_socket;
+ m_socket = 0;
+ }
+ if (m_process) {
+ delete m_process;
+ m_process = 0;
+ }
+}
+
+void ParserTests::testHelgrindSample1()
+{
+ initTest(QLatin1String("helgrind-output-sample1.xml"));
+
+ QList<Error> expectedErrors;
+ {
+ Error error1;
+ error1.setUnique(0x0);
+ error1.setTid(1);
+ error1.setKind(LockOrder);
+ error1.setWhat(QLatin1String("Thread #1: lock order \"0xA39C270 before 0xA3AC010\" violated"));
+ error1.setHelgrindThreadId(1);
+ Stack stack1;
+ Frame frame11;
+ frame11.setInstructionPointer(0x4C2B806);
+ frame11.setObject(QLatin1String("/usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so"));
+ frame11.setFunctionName(QLatin1String("QMutex::lock()"));
+ frame11.setDirectory(QLatin1String("/build/buildd/valgrind-3.6.0~svn20100212/helgrind"));
+ frame11.setFile(QLatin1String("hg_intercepts.c"));
+ frame11.setLine(1988);
+ Frame frame12;
+ frame12.setInstructionPointer(0x72E57EE);
+ frame12.setObject(QLatin1String("/home/frank/local/qt4-4.6.3-shared-debug/lib/libQtCore.so.4.6.3"));
+ frame12.setFunctionName(QLatin1String("QMutexLocker::relock()"));
+ frame12.setDirectory(QLatin1String("/home/frank/source/tarballs/qt-4.6.3-build/src/corelib/../../include/QtCore/../../src/corelib/thread"));
+ frame12.setFile(QLatin1String("qmutex.h"));
+ frame12.setLine(120);
+ stack1.setFrames(QVector<Frame>() << frame11 << frame12);
+
+ Stack stack2;
+ stack2.setAuxWhat(QLatin1String("Required order was established by acquisition of lock at 0xA39C270"));
+ Frame frame21;
+ frame21.setInstructionPointer(0x4C2B806);
+ frame21.setObject(QLatin1String("/usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so"));
+ frame21.setFunctionName(QLatin1String("QMutex::lock()"));
+ frame21.setDirectory(QLatin1String("/build/buildd/valgrind-3.6.0~svn20100212/helgrind"));
+ frame21.setFile(QLatin1String("hg_intercepts.c"));
+ frame21.setLine(1989);
+ Frame frame22;
+ frame22.setInstructionPointer(0x72E57EE);
+ frame22.setObject(QLatin1String("/home/frank/local/qt4-4.6.3-shared-debug/lib/libQtCore.so.4.6.3"));
+ frame22.setFunctionName(QLatin1String("QMutexLocker::relock()"));
+ frame22.setDirectory(QLatin1String("/home/frank/source/tarballs/qt-4.6.3-build/src/corelib/../../include/QtCore/../../src/corelib/thread"));
+ frame22.setFile(QLatin1String("qmutex.h"));
+ frame22.setLine(121);
+ stack2.setFrames(QVector<Frame>() << frame21 << frame22);
+
+ Stack stack3;
+ stack3.setAuxWhat(QLatin1String("followed by a later acquisition of lock at 0xA3AC010"));
+ Frame frame31;
+ frame31.setInstructionPointer(0x4C2B806);
+ frame31.setObject(QLatin1String("/usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so"));
+ frame31.setFunctionName(QLatin1String("QMutex::lock()"));
+ frame31.setDirectory(QLatin1String("/build/buildd/valgrind-3.6.0~svn20100212/helgrind"));
+ frame31.setFile(QLatin1String("hg_intercepts.c"));
+ frame31.setLine(1990);
+ Frame frame32;
+ frame32.setInstructionPointer(0x72E57EE);
+ frame32.setObject(QLatin1String("/home/frank/local/qt4-4.6.3-shared-debug/lib/libQtCore.so.4.6.3"));
+ frame32.setFunctionName(QLatin1String("QMutexLocker::relock()"));
+ frame32.setDirectory(QLatin1String("/home/frank/source/tarballs/qt-4.6.3-build/src/corelib/../../include/QtCore/../../src/corelib/thread"));
+ frame32.setFile(QLatin1String("qmutex.h"));
+ frame32.setLine(122);
+
+ stack3.setFrames(QVector<Frame>() << frame31 << frame32);
+ error1.setStacks(QVector<Stack>() << stack1 << stack2 << stack3);
+ expectedErrors.append(error1);
+ }
+
+ Valgrind::XmlProtocol::Parser parser;
+ Recorder rec(&parser);
+
+ parser.parse(m_socket);
+
+ 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;
+
+ 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);
+}
+
+void ParserTests::testMemcheckSample1()
+{
+ initTest(QLatin1String("memcheck-output-sample1.xml"));
+
+ QList<Error> expectedErrors;
+ {
+ Error error;
+ error.setKind(InvalidRead);
+ error.setWhat(QLatin1String("Invalid read of size 4"));
+ error.setUnique(0x9);
+ error.setTid(1);
+ Frame f1;
+ f1.setInstructionPointer(0x6E47964);
+ f1.setObject(QLatin1String("/usr/lib/libQtGui.so.4.7.0"));
+ f1.setFunctionName(QLatin1String("QFrame::frameStyle() const"));
+ f1.setDirectory(QLatin1String("/build/buildd/qt4-x11-4.7.0/src/gui/widgets"));
+ f1.setFile(QLatin1String("qframe.cpp"));
+ f1.setLine(252);
+ Frame f2;
+ f2.setInstructionPointer(0x118F2AF7);
+ f2.setObject(QLatin1String("/usr/lib/kde4/plugins/styles/oxygen.so"));
+ Frame f3;
+ f3.setInstructionPointer(0x6A81671);
+ f3.setObject(QLatin1String("/usr/lib/libQtGui.so.4.7.0"));
+ f3.setFunctionName(QLatin1String("QWidget::event(QEvent*)"));
+ f3.setDirectory(QLatin1String("/build/buildd/qt4-x11-4.7.0/src/gui/kernel"));
+ f3.setFile(QLatin1String("qwidget.cpp"));
+ f3.setLine(8273);
+ Frame f4;
+ f4.setInstructionPointer(0x6A2B6EB);
+ f4.setObject(QLatin1String("/usr/lib/libQtGui.so.4.7.0"));
+ f4.setDirectory(QLatin1String("/build/buildd/qt4-x11-4.7.0/src/gui/kernel"));
+ f4.setFile(QLatin1String("qapplication.cpp"));
+ f4.setFunctionName(QLatin1String("QApplicationPrivate::notify_helper(QObject*, QEvent*)"));
+ f4.setLine(4396);
+ Stack s1;
+ s1.setAuxWhat(QLatin1String("Address 0x11527cb8 is not stack'd, malloc'd or (recently) free'd"));
+ s1.setFrames(QVector<Frame>() << f1 << f2 << f3 << f4);
+ error.setStacks( QVector<Stack>() << s1 );
+
+ expectedErrors << error;
+ }
+
+ QVector<QPair<qint64,qint64> > expectedErrorCounts;
+ expectedErrorCounts.push_back(QPair<qint64,qint64>(9, 2));
+
+ QVector<QPair<QString,qint64> > expectedSuppCounts;
+ expectedSuppCounts.push_back(qMakePair(QString::fromLatin1("X on SUSE11 writev uninit padding"), static_cast<qint64>(12)));
+ expectedSuppCounts.push_back(qMakePair(QString::fromLatin1("dl-hack3-cond-1"), static_cast<qint64>(2)));
+ expectedSuppCounts.push_back(qMakePair(QString::fromLatin1("glibc-2.5.x-on-SUSE-10.2-(PPC)-2a"), static_cast<qint64>(2)));
+
+ Valgrind::XmlProtocol::Parser parser;
+ Recorder rec(&parser);
+
+ parser.parse(m_socket);
+
+ 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;
+
+ 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);
+}
+
+void ParserTests::testMemcheckSample2()
+{
+ initTest(QLatin1String("memcheck-output-sample2.xml"));
+
+ Valgrind::XmlProtocol::Parser parser;
+ Recorder rec(&parser);
+
+ parser.parse(m_socket);
+
+ 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);
+ const QVector<Stack> stacks = errors.first().stacks();
+ QCOMPARE(stacks.size(), 2);
+ QCOMPARE(stacks.first().auxWhat(), QString());
+ QCOMPARE(stacks.last().auxWhat(), QLatin1String("Address 0x11b66c50 is 0 bytes inside a block of size 16 free'd"));
+}
+
+void ParserTests::testMemcheckSample3()
+{
+ initTest(QLatin1String("memcheck-output-sample3.xml"));
+
+ Valgrind::XmlProtocol::Parser parser;
+ Recorder rec(&parser);
+
+ parser.parse(m_socket);
+
+ 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);
+ const QVector<Stack> stacks = error.stacks();
+
+ QCOMPARE(error.unique(), 0x1ll);
+ QCOMPARE(error.what(), QLatin1String("Conditional jump or move depends on uninitialised value(s)"));
+ 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());
+ QCOMPARE(error.suppression().kind(), QLatin1String("Memcheck:Cond"));
+ QVERIFY(!error.suppression().rawText().trimmed().isEmpty());
+
+ // rawtext contains <...> while <name></name> does not
+ QCOMPARE(error.suppression().name(), QLatin1String("insert_a_suppression_name_here"));
+ Suppression sup = error.suppression();
+ sup.setName(QLatin1String("<insert_a_suppression_name_here>"));
+ QCOMPARE(sup.toString().trimmed(), sup.rawText().trimmed());
+
+ QCOMPARE(error.suppression().frames().first().object(),
+ QLatin1String("/usr/lib/kde4/plugins/styles/qtcurve.so"));
+ QVERIFY(error.suppression().frames().first().function().isEmpty());
+ QCOMPARE(error.suppression().frames().last().function(), QLatin1String("main"));
+ 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));
+}
+
+void ParserTests::testMemcheckCharm()
+{
+ // a somewhat larger file, to make sure buffering and partial I/O works ok
+ initTest(QLatin1String("memcheck-output-charm.xml"));
+
+ Valgrind::XmlProtocol::Parser parser;
+ Recorder rec(&parser);
+
+ parser.parse(m_socket);
+
+ 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()));
+}
+
+void ParserTests::testValgrindCrash()
+{
+ initTest(QLatin1String("memcheck-output-sample1.xml"), QStringList() << "--crash");
+
+ Valgrind::XmlProtocol::Parser parser;
+ parser.parse(m_socket);
+ m_process->waitForFinished();
+ QCOMPARE(m_process->state(), QProcess::NotRunning);
+ QCOMPARE(m_process->exitStatus(), QProcess::CrashExit);
+
+ QVERIFY(!parser.errorString().isEmpty());
+ QCOMPARE(m_socket->error(), QAbstractSocket::RemoteHostClosedError);
+ QCOMPARE(parser.errorString(), m_socket->errorString());
+}
+
+void ParserTests::testValgrindGarbage()
+{
+ initTest(QLatin1String("memcheck-output-sample1.xml"), QStringList() << "--garbage");
+
+ Valgrind::XmlProtocol::Parser parser;
+ parser.parse(m_socket);
+ m_process->waitForFinished();
+ QCOMPARE(m_process->state(), QProcess::NotRunning);
+ QCOMPARE(m_process->exitStatus(), QProcess::NormalExit);
+
+ QVERIFY(!parser.errorString().isEmpty());
+ qDebug() << parser.errorString();
+}
+
+void ParserTests::testParserStop()
+{
+ ThreadedParser parser;
+ Valgrind::Memcheck::MemcheckRunner runner;
+ runner.setValgrindExecutable(fakeValgrindExecutable());
+ runner.setParser(&parser);
+ runner.setValgrindArguments(QStringList() << QLatin1String("-i")
+ << dataFile(QLatin1String("memcheck-output-sample1.xml"))
+ << "--wait" << "5");
+ runner.setProcessChannelMode(QProcess::ForwardedChannels);
+
+ runner.start();
+ QTest::qWait(500);
+ runner.stop();
+}
+
+
+void ParserTests::testRealValgrind()
+{
+ QString executable = QProcessEnvironment::systemEnvironment().value("VALGRIND_TEST_BIN", fakeValgrindExecutable());
+ qDebug() << "running exe:" << executable << " HINT: set VALGRIND_TEST_BIN to change this";
+ ThreadedParser parser;
+
+ Valgrind::Memcheck::MemcheckRunner runner;
+ runner.setValgrindExecutable(QString("valgrind"));
+ runner.setDebuggeeExecutable(executable);
+ runner.setParser(&parser);
+ RunnerDumper dumper(&runner, &parser);
+ runner.start();
+ runner.waitForFinished();
+}
+
+void ParserTests::testValgrindStartError_data()
+{
+ QTest::addColumn<QString>("valgrindExe");
+ QTest::addColumn<QStringList>("valgrindArgs");
+ QTest::addColumn<QString>("debuggee");
+ QTest::addColumn<QString>("debuggeeArgs");
+
+ QTest::newRow("invalid_client") << QString("valgrind") << QStringList()
+ << QString("please-dont-let-this-app-exist") << QString();
+
+ QTest::newRow("invalid_valgrind") << QString("valgrind-that-does-not-exist") << QStringList()
+ << fakeValgrindExecutable() << QString();
+
+ QTest::newRow("invalid_valgrind_args") << QString("valgrind") << (QStringList() << "--foobar-fail")
+ << fakeValgrindExecutable() << QString();
+}
+
+void ParserTests::testValgrindStartError()
+{
+ QFETCH(QString, valgrindExe);
+ QFETCH(QStringList, valgrindArgs);
+ QFETCH(QString, debuggee);
+ QFETCH(QString, debuggeeArgs);
+
+ ThreadedParser parser;
+
+ Valgrind::Memcheck::MemcheckRunner runner;
+ runner.setParser(&parser);
+ runner.setValgrindExecutable(valgrindExe);
+ runner.setValgrindArguments(valgrindArgs);
+ runner.setDebuggeeExecutable(debuggee);
+ runner.setDebuggeeArguments(debuggeeArgs);
+ RunnerDumper dumper(&runner, &parser);
+ runner.start();
+ runner.waitForFinished();
+ QVERIFY(dumper.m_errorReceived);
+ // just finish without deadlock and we are fine
+}
+
+QTEST_MAIN(ParserTests)
diff --git a/tests/valgrind/memcheck/parsertests.h b/tests/valgrind/memcheck/parsertests.h
new file mode 100644
index 0000000000..42f564413b
--- /dev/null
+++ b/tests/valgrind/memcheck/parsertests.h
@@ -0,0 +1,186 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator Analyzer Tools
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Author: Frank Osterfeld, KDAB (frank.osterfeld@kdab.com)
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef PARSERTESTS_H
+#define PARSERTESTS_H
+
+#include <QtCore/QObject>
+#include <QtCore/QPair>
+#include <QtCore/QStringList>
+#include <QtCore/QVector>
+#include <QtCore/QDebug>
+
+#include <valgrind/xmlprotocol/error.h>
+#include <valgrind/xmlprotocol/status.h>
+#include <valgrind/xmlprotocol/threadedparser.h>
+#include <valgrind/xmlprotocol/parser.h>
+#include <valgrind/memcheck/memcheckrunner.h>
+
+QT_BEGIN_NAMESPACE
+class QTcpServer;
+class QTcpSocket;
+class QProcess;
+QT_END_NAMESPACE
+
+void dumpError(const Valgrind::XmlProtocol::Error &e);
+
+class Recorder : public QObject
+{
+ Q_OBJECT
+public:
+ explicit Recorder(Valgrind::XmlProtocol::Parser *parser, QObject *parent = 0)
+ : QObject(parent)
+ {
+ connect(parser, SIGNAL(error(Valgrind::XmlProtocol::Error)),
+ this, SLOT(error(Valgrind::XmlProtocol::Error)));
+ connect(parser, SIGNAL(errorCount(qint64, qint64)),
+ this, SLOT(errorCount(qint64, qint64)));
+ connect(parser, SIGNAL(suppressionCount(QString, qint64)),
+ this, SLOT(suppressionCount(QString, qint64)));
+ }
+
+ QList<Valgrind::XmlProtocol::Error> errors;
+ QVector<QPair<qint64,qint64> > errorcounts;
+ QVector<QPair<QString,qint64> > suppcounts;
+
+public Q_SLOTS:
+ void error(const Valgrind::XmlProtocol::Error &err)
+ {
+ errors.append(err);
+ }
+
+ void errorCount(qint64 uniq, qint64 count)
+ {
+ errorcounts.push_back(qMakePair(uniq, count));
+ }
+
+ void suppressionCount(const QString &name, qint64 count)
+ {
+ suppcounts.push_back(qMakePair(name, count));
+ }
+
+};
+
+class RunnerDumper : public QObject
+{
+ Q_OBJECT
+
+public:
+ explicit RunnerDumper(Valgrind::Memcheck::MemcheckRunner *runner, Valgrind::XmlProtocol::ThreadedParser *parser)
+ : QObject()
+ , m_errorReceived(false)
+ {
+ connect(parser, SIGNAL(error(Valgrind::XmlProtocol::Error)),
+ this, SLOT(error(Valgrind::XmlProtocol::Error)));
+ connect(parser, SIGNAL(internalError(QString)),
+ this, SLOT(internalError(QString)));
+ connect(parser, SIGNAL(status(Valgrind::XmlProtocol::Status)),
+ this, SLOT(status(Valgrind::XmlProtocol::Status)));
+ connect(runner, SIGNAL(standardErrorReceived(QByteArray)),
+ this, SLOT(standardErrorReceived(QByteArray)));
+ connect(runner, SIGNAL(standardOutputReceived(QByteArray)),
+ this, SLOT(standardOutputReceived(QByteArray)));
+ connect(runner, SIGNAL(logMessageReceived(QByteArray)),
+ this, SLOT(logMessageReceived(QByteArray)));
+ connect(runner, SIGNAL(processErrorReceived(QString, QProcess::ProcessError)),
+ this, SLOT(processErrorReceived(QString)));
+ }
+
+public slots:
+ void error(const Valgrind::XmlProtocol::Error &e)
+ {
+ qDebug() << "error received";
+ dumpError(e);
+ }
+ void internalError(const QString& error)
+ {
+ qDebug() << "internal error received:" << error;
+ }
+ void standardErrorReceived(const QByteArray &err)
+ {
+ Q_UNUSED(err);
+ // qDebug() << "STDERR received:" << err; // this can be a lot of text
+ }
+ void standardOutputReceived(const QByteArray &out)
+ {
+ qDebug() << "STDOUT received:" << out;
+ }
+ void status(const Valgrind::XmlProtocol::Status &status)
+ {
+ qDebug() << "status received:" << status.state() << status.time();
+ }
+ void logMessageReceived(const QByteArray &log)
+ {
+ qDebug() << "log message received:" << log;
+ }
+ void processErrorReceived(const QString &s)
+ {
+ Q_UNUSED(s);
+ // qDebug() << "error received:" << s; // this can be a lot of text
+ m_errorReceived = true;
+ }
+
+public:
+ bool m_errorReceived;
+
+};
+
+class ParserTests : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+ void initTestCase();
+ void cleanup();
+
+ void testMemcheckSample1();
+ void testMemcheckSample2();
+ void testMemcheckSample3();
+ void testMemcheckCharm();
+ void testHelgrindSample1();
+
+ void testValgrindCrash();
+ void testValgrindGarbage();
+
+ void testParserStop();
+ void testRealValgrind();
+ void testValgrindStartError_data();
+ void testValgrindStartError();
+
+private:
+ void initTest(const QLatin1String &testfile, const QStringList &otherArgs = QStringList());
+
+ QTcpServer *m_server;
+ QProcess *m_process;
+ QTcpSocket *m_socket;
+};
+
+#endif // PARSERTESTS_H
diff --git a/tests/valgrind/memcheck/parsertests.pro b/tests/valgrind/memcheck/parsertests.pro
new file mode 100644
index 0000000000..92eb6eca8c
--- /dev/null
+++ b/tests/valgrind/memcheck/parsertests.pro
@@ -0,0 +1,19 @@
+TEMPLATE = app
+TARGET = parsertests
+
+macx:CONFIG -= app_bundle
+
+QT += testlib network
+
+DEFINES += "PARSERTESTS_DATA_DIR=\"\\\"$$PWD/data\\\"\""
+
+DEFINES += "VALGRIND_FAKE_PATH="\\\"$$IDE_BUILD_TREE/src/tools/valgrindfake/valgrind-fake\\\""
+
+!win32 {
+ include(../../../qtcreator.pri)
+ include(../../../src/libs/valgrind/valgrind.pri)
+}
+
+SOURCES += parsertests.cpp
+
+HEADERS += parsertests.h
diff --git a/tests/valgrind/memcheck/testapps/free1/free1.pro b/tests/valgrind/memcheck/testapps/free1/free1.pro
new file mode 100644
index 0000000000..0b7ac8d808
--- /dev/null
+++ b/tests/valgrind/memcheck/testapps/free1/free1.pro
@@ -0,0 +1,8 @@
+TEMPLATE = app
+TARGET = free1
+
+QT -= core gui
+
+macx:CONFIG -= app_bundle
+
+SOURCES += main.cpp
diff --git a/tests/valgrind/memcheck/testapps/free1/main.cpp b/tests/valgrind/memcheck/testapps/free1/main.cpp
new file mode 100644
index 0000000000..7b84756558
--- /dev/null
+++ b/tests/valgrind/memcheck/testapps/free1/main.cpp
@@ -0,0 +1,9 @@
+#include <cstdlib>
+
+int main()
+{
+ int *p = new int;
+ delete p;
+ delete p;
+ return 0;
+}
diff --git a/tests/valgrind/memcheck/testapps/free2/free2.pro b/tests/valgrind/memcheck/testapps/free2/free2.pro
new file mode 100644
index 0000000000..1c1f7a5098
--- /dev/null
+++ b/tests/valgrind/memcheck/testapps/free2/free2.pro
@@ -0,0 +1,8 @@
+TEMPLATE = app
+TARGET = free2
+
+QT -= core gui
+
+macx:CONFIG -= app_bundle
+
+SOURCES += main.cpp
diff --git a/tests/valgrind/memcheck/testapps/free2/main.cpp b/tests/valgrind/memcheck/testapps/free2/main.cpp
new file mode 100644
index 0000000000..cb4e295c61
--- /dev/null
+++ b/tests/valgrind/memcheck/testapps/free2/main.cpp
@@ -0,0 +1,8 @@
+#include <cstdlib>
+
+int main()
+{
+ int *p = new int;
+ free(p);
+ return 0;
+}
diff --git a/tests/valgrind/memcheck/testapps/invalidjump/invalidjump.pro b/tests/valgrind/memcheck/testapps/invalidjump/invalidjump.pro
new file mode 100644
index 0000000000..7f7a231327
--- /dev/null
+++ b/tests/valgrind/memcheck/testapps/invalidjump/invalidjump.pro
@@ -0,0 +1,8 @@
+TEMPLATE = app
+TARGET = invalidjump
+
+QT -= core gui
+
+macx:CONFIG -= app_bundle
+
+SOURCES += main.cpp
diff --git a/tests/valgrind/memcheck/testapps/invalidjump/main.cpp b/tests/valgrind/memcheck/testapps/invalidjump/main.cpp
new file mode 100644
index 0000000000..7c608d4023
--- /dev/null
+++ b/tests/valgrind/memcheck/testapps/invalidjump/main.cpp
@@ -0,0 +1,8 @@
+void foo() { }
+
+int main()
+{
+ void (*fooPtr)() = 0;
+ fooPtr();
+ return 0;
+}
diff --git a/tests/valgrind/memcheck/testapps/leak1/leak1.pro b/tests/valgrind/memcheck/testapps/leak1/leak1.pro
new file mode 100644
index 0000000000..2b5b6b8be8
--- /dev/null
+++ b/tests/valgrind/memcheck/testapps/leak1/leak1.pro
@@ -0,0 +1,8 @@
+TEMPLATE = app
+TARGET = leak1
+
+QT += core
+
+macx:CONFIG -= app_bundle
+
+SOURCES += main.cpp
diff --git a/tests/valgrind/memcheck/testapps/leak1/main.cpp b/tests/valgrind/memcheck/testapps/leak1/main.cpp
new file mode 100644
index 0000000000..540a6806f0
--- /dev/null
+++ b/tests/valgrind/memcheck/testapps/leak1/main.cpp
@@ -0,0 +1,7 @@
+#include <qglobal.h>
+
+int main()
+{
+ qint64 *i = new qint64;
+ return 0;
+}
diff --git a/tests/valgrind/memcheck/testapps/leak2/leak2.pro b/tests/valgrind/memcheck/testapps/leak2/leak2.pro
new file mode 100644
index 0000000000..8b9b2717a7
--- /dev/null
+++ b/tests/valgrind/memcheck/testapps/leak2/leak2.pro
@@ -0,0 +1,8 @@
+TEMPLATE = app
+TARGET = leak2
+
+QT += core
+
+macx:CONFIG -= app_bundle
+
+SOURCES += main.cpp
diff --git a/tests/valgrind/memcheck/testapps/leak2/main.cpp b/tests/valgrind/memcheck/testapps/leak2/main.cpp
new file mode 100644
index 0000000000..6a6ec0745b
--- /dev/null
+++ b/tests/valgrind/memcheck/testapps/leak2/main.cpp
@@ -0,0 +1,13 @@
+#include <string.h>
+
+char *lower;
+
+int main()
+{
+ lower = strdup("asdf");
+
+ while (*lower)
+ *(lower++);
+
+ return 0;
+}
diff --git a/tests/valgrind/memcheck/testapps/leak3/leak3.pro b/tests/valgrind/memcheck/testapps/leak3/leak3.pro
new file mode 100644
index 0000000000..aaefab13df
--- /dev/null
+++ b/tests/valgrind/memcheck/testapps/leak3/leak3.pro
@@ -0,0 +1,8 @@
+TEMPLATE = app
+TARGET = leak3
+
+QT += core
+
+macx:CONFIG -= app_bundle
+
+SOURCES += main.cpp
diff --git a/tests/valgrind/memcheck/testapps/leak3/main.cpp b/tests/valgrind/memcheck/testapps/leak3/main.cpp
new file mode 100644
index 0000000000..13735b6708
--- /dev/null
+++ b/tests/valgrind/memcheck/testapps/leak3/main.cpp
@@ -0,0 +1,10 @@
+#include <string.h>
+
+char *lower;
+
+int main()
+{
+ lower = strdup("asdf");
+
+ return 0;
+}
diff --git a/tests/valgrind/memcheck/testapps/leak4/leak4.pro b/tests/valgrind/memcheck/testapps/leak4/leak4.pro
new file mode 100644
index 0000000000..ebbafbd51a
--- /dev/null
+++ b/tests/valgrind/memcheck/testapps/leak4/leak4.pro
@@ -0,0 +1,8 @@
+TEMPLATE = app
+TARGET = leak4
+
+QT += core
+
+macx:CONFIG -= app_bundle
+
+SOURCES += main.cpp
diff --git a/tests/valgrind/memcheck/testapps/leak4/main.cpp b/tests/valgrind/memcheck/testapps/leak4/main.cpp
new file mode 100644
index 0000000000..d087435339
--- /dev/null
+++ b/tests/valgrind/memcheck/testapps/leak4/main.cpp
@@ -0,0 +1,17 @@
+#include <qglobal.h>
+
+struct Foo
+{
+ Foo()
+ : num(new qint64)
+ {}
+
+ qint64 *num;
+};
+
+int main()
+{
+ Foo *f = new Foo;
+
+ return 0;
+}
diff --git a/tests/valgrind/memcheck/testapps/overlap/main.cpp b/tests/valgrind/memcheck/testapps/overlap/main.cpp
new file mode 100644
index 0000000000..0066239a10
--- /dev/null
+++ b/tests/valgrind/memcheck/testapps/overlap/main.cpp
@@ -0,0 +1,9 @@
+#include <string.h>
+
+int main()
+{
+ int *i = new int[10];
+ memcpy(i, &i[1], 20);
+ delete[] i;
+ return 0;
+}
diff --git a/tests/valgrind/memcheck/testapps/overlap/overlap.pro b/tests/valgrind/memcheck/testapps/overlap/overlap.pro
new file mode 100644
index 0000000000..cad970b1fa
--- /dev/null
+++ b/tests/valgrind/memcheck/testapps/overlap/overlap.pro
@@ -0,0 +1,8 @@
+TEMPLATE = app
+TARGET = overlap
+
+QT -= core gui
+
+macx:CONFIG -= app_bundle
+
+SOURCES += main.cpp
diff --git a/tests/valgrind/memcheck/testapps/syscall/main.cpp b/tests/valgrind/memcheck/testapps/syscall/main.cpp
new file mode 100644
index 0000000000..fcf3363791
--- /dev/null
+++ b/tests/valgrind/memcheck/testapps/syscall/main.cpp
@@ -0,0 +1,5 @@
+int main()
+{
+ int i;
+ return i;
+}
diff --git a/tests/valgrind/memcheck/testapps/syscall/syscall.pro b/tests/valgrind/memcheck/testapps/syscall/syscall.pro
new file mode 100644
index 0000000000..e54d4d379e
--- /dev/null
+++ b/tests/valgrind/memcheck/testapps/syscall/syscall.pro
@@ -0,0 +1,8 @@
+TEMPLATE = app
+TARGET = syscall
+
+QT += core
+
+macx:CONFIG -= app_bundle
+
+SOURCES += main.cpp
diff --git a/tests/valgrind/memcheck/testapps/testapps.pro b/tests/valgrind/memcheck/testapps/testapps.pro
new file mode 100644
index 0000000000..90490cf34c
--- /dev/null
+++ b/tests/valgrind/memcheck/testapps/testapps.pro
@@ -0,0 +1,4 @@
+TEMPLATE = subdirs
+
+SUBDIRS += leak1 leak2 leak3 leak4 uninit1 uninit2 syscall free1 uninit3 free2 invalidjump \
+ overlap
diff --git a/tests/valgrind/memcheck/testapps/uninit1/main.cpp b/tests/valgrind/memcheck/testapps/uninit1/main.cpp
new file mode 100644
index 0000000000..ab571da180
--- /dev/null
+++ b/tests/valgrind/memcheck/testapps/uninit1/main.cpp
@@ -0,0 +1,9 @@
+int main()
+{
+ bool b;
+ if (b) {
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/tests/valgrind/memcheck/testapps/uninit1/uninit1.pro b/tests/valgrind/memcheck/testapps/uninit1/uninit1.pro
new file mode 100644
index 0000000000..68843829d5
--- /dev/null
+++ b/tests/valgrind/memcheck/testapps/uninit1/uninit1.pro
@@ -0,0 +1,8 @@
+TEMPLATE = app
+TARGET = uninit1
+
+QT += core
+
+macx:CONFIG -= app_bundle
+
+SOURCES += main.cpp
diff --git a/tests/valgrind/memcheck/testapps/uninit2/main.cpp b/tests/valgrind/memcheck/testapps/uninit2/main.cpp
new file mode 100644
index 0000000000..75cc9bdfa3
--- /dev/null
+++ b/tests/valgrind/memcheck/testapps/uninit2/main.cpp
@@ -0,0 +1,7 @@
+int main()
+{
+ int *i;
+ *i = 5;
+
+ return 0;
+}
diff --git a/tests/valgrind/memcheck/testapps/uninit2/uninit2.pro b/tests/valgrind/memcheck/testapps/uninit2/uninit2.pro
new file mode 100644
index 0000000000..7e5f89e0b5
--- /dev/null
+++ b/tests/valgrind/memcheck/testapps/uninit2/uninit2.pro
@@ -0,0 +1,8 @@
+TEMPLATE = app
+TARGET = uninit2
+
+QT -= core gui
+
+macx:CONFIG -= app_bundle
+
+SOURCES += main.cpp
diff --git a/tests/valgrind/memcheck/testapps/uninit3/main.cpp b/tests/valgrind/memcheck/testapps/uninit3/main.cpp
new file mode 100644
index 0000000000..b0c392d211
--- /dev/null
+++ b/tests/valgrind/memcheck/testapps/uninit3/main.cpp
@@ -0,0 +1,5 @@
+int main()
+{
+ int *i;
+ return *i;
+}
diff --git a/tests/valgrind/memcheck/testapps/uninit3/uninit3.pro b/tests/valgrind/memcheck/testapps/uninit3/uninit3.pro
new file mode 100644
index 0000000000..102d0cae83
--- /dev/null
+++ b/tests/valgrind/memcheck/testapps/uninit3/uninit3.pro
@@ -0,0 +1,8 @@
+TEMPLATE = app
+TARGET = uninit3
+
+QT -= core gui
+
+macx:CONFIG -= app_bundle
+
+SOURCES += main.cpp
diff --git a/tests/valgrind/memcheck/testrunner.cpp b/tests/valgrind/memcheck/testrunner.cpp
new file mode 100644
index 0000000000..5d6f5bc19a
--- /dev/null
+++ b/tests/valgrind/memcheck/testrunner.cpp
@@ -0,0 +1,703 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Author: Milian Wolff, KDAB (milian.wolff@kdab.com)
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** No Commercial Usage
+**
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**************************************************************************/
+
+#include "testrunner.h"
+
+#include <valgrind/xmlprotocol/frame.h>
+#include <valgrind/xmlprotocol/stack.h>
+#include <valgrind/xmlprotocol/suppression.h>
+#include <valgrind/xmlprotocol/threadedparser.h>
+#include <valgrind/xmlprotocol/parser.h>
+#include <valgrind/memcheck/memcheckrunner.h>
+
+#include <QDebug>
+#include <QTest>
+#include <QDir>
+#include <QSignalSpy>
+
+const QString appSrcDir(TESTRUNNER_SRC_DIR);
+const QString appBinDir(TESTRUNNER_APP_DIR);
+
+QString srcDirForApp(const QString &app)
+{
+ return appSrcDir + QDir::separator() + app;
+}
+
+QTEST_MAIN(Valgrind::TestRunner)
+
+using namespace Valgrind;
+using namespace Valgrind::XmlProtocol;
+using namespace Valgrind::Memcheck;
+
+//BEGIN Test Helpers and boilterplate code
+
+TestRunner::TestRunner(QObject *parent)
+ : QObject(parent),
+ m_parser(0),
+ m_runner(0)
+{
+ qRegisterMetaType<Error>();
+}
+
+QString TestRunner::runTestBinary(const QString &binary, const QStringList &vArgs)
+{
+ const QString binPath = appBinDir + QDir::separator() + binary;
+ Q_ASSERT(QFileInfo(binPath).isExecutable());
+ m_runner->setValgrindArguments(QStringList() << "--num-callers=50" << "--track-origins=yes" << vArgs);
+ m_runner->setDebuggeeExecutable(binPath);
+ m_runner->start();
+ m_runner->waitForFinished();
+ return binPath;
+}
+
+void TestRunner::logMessageReceived(const QByteArray &message)
+{
+ qDebug() << "log message received:" << message;
+ m_logMessages << message;
+}
+
+void TestRunner::internalError(const QString &error)
+{
+ if (!m_expectCrash)
+ QFAIL(qPrintable(error));
+ else
+ qDebug() << "expected crash:" << error;
+}
+
+void TestRunner::error(const Error &error)
+{
+ m_errors << error;
+}
+
+void TestRunner::cleanup()
+{
+ Q_ASSERT(m_runner);
+ delete m_runner;
+ m_runner = 0;
+ Q_ASSERT(m_parser);
+ delete m_parser;
+ m_parser = 0;
+
+ m_logMessages.clear();
+ m_errors.clear();
+ m_expectCrash = false;
+}
+
+void TestRunner::init()
+{
+ Q_ASSERT(m_logMessages.isEmpty());
+
+ Q_ASSERT(!m_runner);
+ m_runner = new MemcheckRunner;
+ m_runner->setValgrindExecutable(QLatin1String("valgrind"));
+ m_runner->setProcessChannelMode(QProcess::ForwardedChannels);
+ connect(m_runner, SIGNAL(logMessageReceived(QByteArray)),
+ this, SLOT(logMessageReceived(QByteArray)));
+ connect(m_runner, SIGNAL(processErrorReceived(QString, QProcess::ProcessError)),
+ this, SLOT(internalError(QString)));
+ Q_ASSERT(!m_parser);
+ m_parser = new ThreadedParser;
+ connect(m_parser, SIGNAL(internalError(QString)),
+ this, SLOT(internalError(QString)));
+ connect(m_parser, SIGNAL(error(Valgrind::XmlProtocol::Error)),
+ this, SLOT(error(Valgrind::XmlProtocol::Error)));
+
+ m_runner->setParser(m_parser);
+}
+
+//BEGIN: Actual test cases
+
+void TestRunner::testLeak1()
+{
+ const QString binary = runTestBinary(QLatin1String("leak1/leak1"));
+
+ QVERIFY(m_logMessages.isEmpty());
+
+ QCOMPARE(m_errors.count(), 1);
+ const Error error = m_errors.first();
+ QCOMPARE(error.kind(), int(Leak_DefinitelyLost));
+ QCOMPARE(error.leakedBlocks(), qint64(1));
+ QCOMPARE(error.leakedBytes(), quint64(8));
+ QCOMPARE(error.stacks().count(), 1);
+ const Stack stack = error.stacks().first();
+ QCOMPARE(stack.line(), qint64(-1));
+ QCOMPARE(stack.frames().count(), 2);
+ {
+ const Frame frame = stack.frames().at(0);
+ QCOMPARE(frame.functionName(), QString("operator new(unsigned long)"));
+ }
+ {
+ const Frame frame = stack.frames().at(1);
+ QCOMPARE(frame.functionName(), QString("main"));
+ QCOMPARE(frame.line(), 5);
+
+ QCOMPARE(frame.object(), binary);
+ QCOMPARE(frame.file(), QLatin1String("main.cpp"));
+ QCOMPARE(QDir::cleanPath(frame.directory()), srcDirForApp("leak1"));
+ }
+}
+
+void TestRunner::testLeak2()
+{
+ const QString binary = runTestBinary(QLatin1String("leak2/leak2"));
+
+ QVERIFY(m_logMessages.isEmpty());
+
+ QCOMPARE(m_errors.count(), 1);
+ const Error error = m_errors.first();
+ QCOMPARE(error.kind(), int(Leak_PossiblyLost));
+ QCOMPARE(error.leakedBlocks(), qint64(1));
+ QCOMPARE(error.leakedBytes(), quint64(5));
+ QCOMPARE(error.stacks().count(), 1);
+ const Stack stack = error.stacks().first();
+ QCOMPARE(stack.line(), qint64(-1));
+ QCOMPARE(stack.frames().count(), 3);
+ {
+ const Frame frame = stack.frames().at(0);
+ QCOMPARE(frame.functionName(), QString("malloc"));
+ }
+ {
+ const Frame frame = stack.frames().at(1);
+ QCOMPARE(frame.functionName(), QString("strdup"));
+ }
+ {
+ const Frame frame = stack.frames().at(2);
+ QCOMPARE(frame.functionName(), QString("main"));
+ QCOMPARE(frame.line(), 7);
+
+ QCOMPARE(frame.object(), binary);
+ QCOMPARE(frame.file(), QLatin1String("main.cpp"));
+ QCOMPARE(QDir::cleanPath(frame.directory()), srcDirForApp("leak2"));
+ }
+}
+
+void TestRunner::testLeak3()
+{
+ const QString binary = runTestBinary(QLatin1String("leak3/leak3"), QStringList() << "--show-reachable=yes");
+
+ QVERIFY(m_logMessages.isEmpty());
+
+ QCOMPARE(m_errors.count(), 1);
+ const Error error = m_errors.first();
+ QCOMPARE(error.kind(), int(Leak_StillReachable));
+ QCOMPARE(error.leakedBlocks(), qint64(1));
+ QCOMPARE(error.leakedBytes(), quint64(5));
+ QCOMPARE(error.stacks().count(), 1);
+ const Stack stack = error.stacks().first();
+ QCOMPARE(stack.line(), qint64(-1));
+ QCOMPARE(stack.frames().count(), 3);
+ {
+ const Frame frame = stack.frames().at(0);
+ QCOMPARE(frame.functionName(), QString("malloc"));
+ }
+ {
+ const Frame frame = stack.frames().at(1);
+ QCOMPARE(frame.functionName(), QString("strdup"));
+ }
+ {
+ const Frame frame = stack.frames().at(2);
+ QCOMPARE(frame.functionName(), QString("main"));
+ QCOMPARE(frame.line(), 7);
+
+ QCOMPARE(frame.object(), binary);
+ QCOMPARE(frame.file(), QLatin1String("main.cpp"));
+ QCOMPARE(QDir::cleanPath(frame.directory()), srcDirForApp("leak3"));
+ }
+}
+
+void TestRunner::testLeak4()
+{
+ const QString app("leak4");
+ const QString binary = runTestBinary(app + QDir::separator() + app,
+ QStringList() << "--show-reachable=yes");
+ const QString srcDir = srcDirForApp("leak4");
+
+ QVERIFY(m_logMessages.isEmpty());
+
+ QCOMPARE(m_errors.count(), 2);
+ //BEGIN first error
+ {
+ const Error error = m_errors.first();
+ QCOMPARE(error.kind(), int(Leak_IndirectlyLost));
+ QCOMPARE(error.leakedBlocks(), qint64(1));
+ QCOMPARE(error.leakedBytes(), quint64(8));
+ QCOMPARE(error.stacks().count(), 1);
+ const Stack stack = error.stacks().first();
+ QCOMPARE(stack.line(), qint64(-1));
+ QCOMPARE(stack.frames().count(), 3);
+ {
+ const Frame frame = stack.frames().at(0);
+ QCOMPARE(frame.functionName(), QString("operator new(unsigned long)"));
+ }
+ {
+ const Frame frame = stack.frames().at(2);
+ QCOMPARE(frame.functionName(), QString("main"));
+ QCOMPARE(frame.line(), 13);
+
+ QCOMPARE(frame.object(), binary);
+ QCOMPARE(frame.file(), QLatin1String("main.cpp"));
+ QCOMPARE(QDir::cleanPath(frame.directory()), srcDir);
+ }
+ {
+ const Frame frame = stack.frames().at(1);
+ QCOMPARE(frame.functionName(), QString("foo::foo()"));
+ QCOMPARE(frame.line(), 5);
+
+ QCOMPARE(frame.object(), binary);
+ QCOMPARE(frame.file(), QLatin1String("main.cpp"));
+ QCOMPARE(QDir::cleanPath(frame.directory()), srcDir);
+ }
+ {
+ const Frame frame = stack.frames().at(2);
+ QCOMPARE(frame.functionName(), QString("main"));
+ QCOMPARE(frame.line(), 13);
+
+ QCOMPARE(frame.object(), binary);
+ QCOMPARE(frame.file(), QLatin1String("main.cpp"));
+ QCOMPARE(QDir::cleanPath(frame.directory()), srcDir);
+ }
+ }
+ //BEGIN second error
+ {
+ const Error error = m_errors.last();
+ QCOMPARE(error.kind(), int(Leak_DefinitelyLost));
+ QCOMPARE(error.leakedBlocks(), qint64(1));
+ QCOMPARE(error.leakedBytes(), quint64(16));
+ QCOMPARE(error.stacks().count(), 1);
+ const Stack stack = error.stacks().first();
+ QCOMPARE(stack.line(), qint64(-1));
+ QCOMPARE(stack.frames().count(), 2);
+ {
+ const Frame frame = stack.frames().at(0);
+ QCOMPARE(frame.functionName(), QString("operator new(unsigned long)"));
+ }
+ {
+ const Frame frame = stack.frames().at(1);
+ QCOMPARE(frame.functionName(), QString("main"));
+ QCOMPARE(frame.line(), 13);
+
+ QCOMPARE(frame.object(), binary);
+ QCOMPARE(frame.file(), QLatin1String("main.cpp"));
+ QCOMPARE(QDir::cleanPath(frame.directory()), srcDir);
+ }
+ }
+}
+
+void TestRunner::uninit1()
+{
+ const QString app("uninit1");
+ const QString binary = runTestBinary(app + QDir::separator() + app);
+ const QString srcDir = srcDirForApp(app);
+
+ QVERIFY(m_logMessages.isEmpty());
+
+ QCOMPARE(m_errors.count(), 1);
+ const Error error = m_errors.first();
+ QCOMPARE(error.kind(), int(UninitCondition));
+ QCOMPARE(error.stacks().count(), 2);
+ //BEGIN first stack
+ {
+ const Stack stack = error.stacks().first();
+ QCOMPARE(stack.line(), qint64(-1));
+ QCOMPARE(stack.frames().count(), 1);
+
+ const Frame frame = stack.frames().first();
+ QCOMPARE(frame.functionName(), QString("main"));
+ QCOMPARE(frame.line(), 4);
+
+ QCOMPARE(frame.object(), binary);
+ QCOMPARE(frame.file(), QLatin1String("main.cpp"));
+ QCOMPARE(QDir::cleanPath(frame.directory()), srcDir);
+ }
+ //BEGIN second stack
+ {
+ const Stack stack = error.stacks().last();
+ QCOMPARE(stack.line(), qint64(-1));
+ QCOMPARE(stack.frames().count(), 1);
+
+ const Frame frame = stack.frames().first();
+ QCOMPARE(frame.functionName(), QString("main"));
+ QCOMPARE(frame.line(), 2);
+
+ QCOMPARE(frame.object(), binary);
+ QCOMPARE(frame.file(), QLatin1String("main.cpp"));
+ QCOMPARE(QDir::cleanPath(frame.directory()), srcDir);
+ }
+}
+
+void TestRunner::uninit2()
+{
+ const QString app("uninit2");
+ m_expectCrash = true;
+ const QString binary = runTestBinary(app + QDir::separator() + app);
+ const QString srcDir = srcDirForApp(app);
+
+ QVERIFY(m_logMessages.isEmpty());
+
+ QCOMPARE(m_errors.count(), 2);
+ //BEGIN first error
+ {
+ const Error error = m_errors.first();
+ QCOMPARE(error.kind(), int(UninitValue));
+ QCOMPARE(error.stacks().count(), 2);
+ //BEGIN first stack
+ {
+ const Stack stack = error.stacks().first();
+ QCOMPARE(stack.line(), qint64(-1));
+ QCOMPARE(stack.frames().count(), 1);
+
+ const Frame frame = stack.frames().first();
+ QCOMPARE(frame.functionName(), QString("main"));
+ QCOMPARE(frame.line(), 4);
+
+ QCOMPARE(frame.object(), binary);
+ QCOMPARE(frame.file(), QLatin1String("main.cpp"));
+ QCOMPARE(QDir::cleanPath(frame.directory()), srcDir);
+ }
+ //BEGIN second stack
+ {
+ const Stack stack = error.stacks().last();
+ QCOMPARE(stack.line(), qint64(-1));
+ QCOMPARE(stack.frames().count(), 1);
+
+ const Frame frame = stack.frames().first();
+ QCOMPARE(frame.functionName(), QString("main"));
+ QCOMPARE(frame.line(), 2);
+
+ QCOMPARE(frame.object(), binary);
+ QCOMPARE(frame.file(), QLatin1String("main.cpp"));
+ QCOMPARE(QDir::cleanPath(frame.directory()), srcDir);
+ }
+ }
+ //BEGIN second error
+ {
+ const Error error = m_errors.last();
+ QCOMPARE(error.kind(), int(InvalidWrite));
+ QCOMPARE(error.stacks().count(), 1);
+
+ const Stack stack = error.stacks().first();
+ QCOMPARE(stack.line(), qint64(-1));
+ QCOMPARE(stack.frames().count(), 1);
+
+ const Frame frame = stack.frames().first();
+ QCOMPARE(frame.functionName(), QString("main"));
+ QCOMPARE(frame.line(), 4);
+
+ QCOMPARE(frame.object(), binary);
+ QCOMPARE(frame.file(), QLatin1String("main.cpp"));
+ QCOMPARE(QDir::cleanPath(frame.directory()), srcDir);
+ }
+}
+
+void TestRunner::uninit3()
+{
+ const QString app("uninit3");
+ m_expectCrash = true;
+ const QString binary = runTestBinary(app + QDir::separator() + app);
+ const QString srcDir = srcDirForApp(app);
+
+ QVERIFY(m_logMessages.isEmpty());
+
+ QCOMPARE(m_errors.count(), 2);
+ //BEGIN first error
+ {
+ const Error error = m_errors.first();
+ QCOMPARE(error.kind(), int(UninitValue));
+ QCOMPARE(error.stacks().count(), 2);
+ //BEGIN first stack
+ {
+ const Stack stack = error.stacks().first();
+ QCOMPARE(stack.line(), qint64(-1));
+ QCOMPARE(stack.frames().count(), 1);
+
+ const Frame frame = stack.frames().first();
+ QCOMPARE(frame.functionName(), QString("main"));
+ QCOMPARE(frame.line(), 3);
+
+ QCOMPARE(frame.object(), binary);
+ QCOMPARE(frame.file(), QLatin1String("main.cpp"));
+ QCOMPARE(QDir::cleanPath(frame.directory()), srcDir);
+ }
+ //BEGIN second stack
+ {
+ const Stack stack = error.stacks().last();
+ QCOMPARE(stack.line(), qint64(-1));
+ QCOMPARE(stack.frames().count(), 1);
+
+ const Frame frame = stack.frames().first();
+ QCOMPARE(frame.functionName(), QString("main"));
+ QCOMPARE(frame.line(), 1);
+
+ QCOMPARE(frame.object(), binary);
+ QCOMPARE(frame.file(), QLatin1String("main.cpp"));
+ QCOMPARE(QDir::cleanPath(frame.directory()), srcDir);
+ }
+ }
+ //BEGIN second error
+ {
+ const Error error = m_errors.last();
+ QCOMPARE(error.kind(), int(InvalidRead));
+ QCOMPARE(error.stacks().count(), 1);
+
+ const Stack stack = error.stacks().first();
+ QCOMPARE(stack.line(), qint64(-1));
+ QCOMPARE(stack.frames().count(), 1);
+
+ const Frame frame = stack.frames().first();
+ QCOMPARE(frame.functionName(), QString("main"));
+ QCOMPARE(frame.line(), 3);
+
+ QCOMPARE(frame.object(), binary);
+ QCOMPARE(frame.file(), QLatin1String("main.cpp"));
+ QCOMPARE(QDir::cleanPath(frame.directory()), srcDir);
+ }
+}
+
+void TestRunner::syscall()
+{
+ const QString app("syscall");
+ const QString binary = runTestBinary(app + QDir::separator() + app);
+ const QString srcDir = srcDirForApp(app);
+
+ QVERIFY(m_logMessages.isEmpty());
+
+ QCOMPARE(m_errors.count(), 1);
+ const Error error = m_errors.first();
+ QCOMPARE(error.kind(), int(SyscallParam));
+ QCOMPARE(error.stacks().count(), 2);
+ //BEGIN first stack
+ {
+ const Stack stack = error.stacks().first();
+ QCOMPARE(stack.line(), qint64(-1));
+ QCOMPARE(stack.frames().count(), 3);
+
+ {
+ ///TODO: is this platform specific?
+ const Frame frame = stack.frames().at(0);
+ QCOMPARE(frame.functionName(), QString("_Exit"));
+ }
+ {
+ const Frame frame = stack.frames().at(1);
+ QCOMPARE(frame.functionName(), QString("exit"));
+ }
+ {
+ const Frame frame = stack.frames().at(2);
+ QCOMPARE(frame.functionName(), QString("(below main)"));
+ }
+ }
+ //BEGIN second stack
+ {
+ const Stack stack = error.stacks().last();
+ QCOMPARE(stack.line(), qint64(-1));
+ QCOMPARE(stack.frames().count(), 1);
+
+ const Frame frame = stack.frames().first();
+ QCOMPARE(frame.functionName(), QString("main"));
+ QCOMPARE(frame.line(), 2);
+
+ QCOMPARE(frame.object(), binary);
+ QCOMPARE(frame.file(), QLatin1String("main.cpp"));
+ QCOMPARE(QDir::cleanPath(frame.directory()), srcDir);
+ }
+}
+
+void TestRunner::free1()
+{
+ const QString app("free1");
+ const QString binary = runTestBinary(app + QDir::separator() + app);
+ const QString srcDir = srcDirForApp(app);
+
+ QVERIFY(m_logMessages.isEmpty());
+
+ QCOMPARE(m_errors.count(), 1);
+ const Error error = m_errors.first();
+ QCOMPARE(error.kind(), int(InvalidFree));
+ QCOMPARE(error.stacks().count(), 2);
+ //BEGIN first stack
+ {
+ const Stack stack = error.stacks().first();
+ QCOMPARE(stack.line(), qint64(-1));
+ QCOMPARE(stack.frames().count(), 2);
+
+ {
+ const Frame frame = stack.frames().first();
+ QCOMPARE(frame.functionName(), QString("operator delete(void*)"));
+ }
+ {
+ const Frame frame = stack.frames().last();
+ QCOMPARE(frame.functionName(), QString("main"));
+ QCOMPARE(frame.line(), 7);
+
+ QCOMPARE(frame.object(), binary);
+ QCOMPARE(frame.file(), QLatin1String("main.cpp"));
+ QCOMPARE(QDir::cleanPath(frame.directory()), srcDir);
+ }
+ }
+ //BEGIN second stack
+ {
+ const Stack stack = error.stacks().last();
+ QCOMPARE(stack.line(), qint64(-1));
+ QCOMPARE(stack.frames().count(), 2);
+
+
+ {
+ const Frame frame = stack.frames().first();
+ QCOMPARE(frame.functionName(), QString("operator delete(void*)"));
+ }
+ {
+ const Frame frame = stack.frames().last();
+ QCOMPARE(frame.functionName(), QString("main"));
+ QCOMPARE(frame.line(), 6);
+
+ QCOMPARE(frame.object(), binary);
+ QCOMPARE(frame.file(), QLatin1String("main.cpp"));
+ QCOMPARE(QDir::cleanPath(frame.directory()), srcDir);
+ }
+ }
+}
+
+void TestRunner::free2()
+{
+ const QString app("free2");
+ const QString binary = runTestBinary(app + QDir::separator() + app);
+ const QString srcDir = srcDirForApp(app);
+
+ QVERIFY(m_logMessages.isEmpty());
+
+ QCOMPARE(m_errors.count(), 1);
+ const Error error = m_errors.first();
+ QCOMPARE(error.kind(), int(MismatchedFree));
+ QCOMPARE(error.stacks().count(), 2);
+ //BEGIN first stack
+ {
+ const Stack stack = error.stacks().first();
+ QCOMPARE(stack.line(), qint64(-1));
+ QCOMPARE(stack.frames().count(), 2);
+
+ {
+ const Frame frame = stack.frames().first();
+ QCOMPARE(frame.functionName(), QString("free"));
+ }
+ {
+ const Frame frame = stack.frames().last();
+ QCOMPARE(frame.functionName(), QString("main"));
+ QCOMPARE(frame.line(), 6);
+
+ QCOMPARE(frame.object(), binary);
+ QCOMPARE(frame.file(), QLatin1String("main.cpp"));
+ QCOMPARE(QDir::cleanPath(frame.directory()), srcDir);
+ }
+ }
+ //BEGIN second stack
+ {
+ const Stack stack = error.stacks().last();
+ QCOMPARE(stack.line(), qint64(-1));
+ QCOMPARE(stack.frames().count(), 2);
+
+
+ {
+ const Frame frame = stack.frames().first();
+ QCOMPARE(frame.functionName(), QString("operator new(unsigned long)"));
+ }
+ {
+ const Frame frame = stack.frames().last();
+ QCOMPARE(frame.functionName(), QString("main"));
+ QCOMPARE(frame.line(), 5);
+
+ QCOMPARE(frame.object(), binary);
+ QCOMPARE(frame.file(), QLatin1String("main.cpp"));
+ QCOMPARE(QDir::cleanPath(frame.directory()), srcDir);
+ }
+ }
+}
+
+void TestRunner::invalidjump()
+{
+ const QString app("invalidjump");
+ m_expectCrash = true;
+ const QString binary = runTestBinary(app + QDir::separator() + app);
+ const QString srcDir = srcDirForApp(app);
+
+ QVERIFY(m_logMessages.isEmpty());
+
+ QCOMPARE(m_errors.count(), 1);
+ const Error error = m_errors.first();
+ QCOMPARE(error.kind(), int(InvalidJump));
+ QCOMPARE(error.stacks().count(), 1);
+ const Stack stack = error.stacks().first();
+ QCOMPARE(stack.line(), qint64(-1));
+ QCOMPARE(stack.frames().count(), 2);
+ QVERIFY(!stack.auxWhat().isEmpty());
+ {
+ const Frame frame = stack.frames().at(0);
+ QCOMPARE(frame.instructionPointer(), quint64(0));
+ }
+ {
+ const Frame frame = stack.frames().at(1);
+ QCOMPARE(frame.functionName(), QString("(below main)"));
+ }
+}
+
+
+void TestRunner::overlap()
+{
+ const QString app("overlap");
+ m_expectCrash = true;
+ const QString binary = runTestBinary(app + QDir::separator() + app);
+ const QString srcDir = srcDirForApp(app);
+
+ QVERIFY(m_logMessages.isEmpty());
+
+ QCOMPARE(m_errors.count(), 1);
+ const Error error = m_errors.first();
+ QCOMPARE(error.kind(), int(Overlap));
+ QCOMPARE(error.stacks().count(), 1);
+ const Stack stack = error.stacks().first();
+ QCOMPARE(stack.line(), qint64(-1));
+ QCOMPARE(stack.frames().count(), 2);
+ {
+ const Frame frame = stack.frames().at(0);
+ QCOMPARE(frame.functionName(), QString("memcpy"));
+ }
+ {
+ const Frame frame = stack.frames().last();
+ QCOMPARE(frame.functionName(), QString("main"));
+ QCOMPARE(frame.line(), 6);
+
+ QCOMPARE(frame.object(), binary);
+ QCOMPARE(frame.file(), QLatin1String("main.cpp"));
+ QCOMPARE(QDir::cleanPath(frame.directory()), srcDir);
+ }
+}
diff --git a/tests/valgrind/memcheck/testrunner.h b/tests/valgrind/memcheck/testrunner.h
new file mode 100644
index 0000000000..64d0d00ad3
--- /dev/null
+++ b/tests/valgrind/memcheck/testrunner.h
@@ -0,0 +1,98 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Author: Milian Wolff, KDAB (milian.wolff@kdab.com)
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** No Commercial Usage
+**
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**************************************************************************/
+
+#ifndef TESTRUNNER_H
+#define TESTRUNNER_H
+
+#include <QObject>
+#include <QStringList>
+
+#include <valgrind/xmlprotocol/error.h>
+
+namespace Valgrind {
+
+namespace XmlProtocol {
+class ThreadedParser;
+}
+
+namespace Memcheck {
+class MemcheckRunner;
+}
+
+class TestRunner : public QObject
+{
+ Q_OBJECT
+
+public:
+ explicit TestRunner(QObject *parent = 0);
+
+private Q_SLOTS:
+ void init();
+ void cleanup();
+
+ void testLeak1();
+ void testLeak2();
+ void testLeak3();
+ void testLeak4();
+
+ void uninit1();
+ void uninit2();
+ void uninit3();
+
+ void free1();
+ void free2();
+
+ void invalidjump();
+ void syscall();
+ void overlap();
+
+private Q_SLOTS:
+ void logMessageReceived(const QByteArray &message);
+ void internalError(const QString &error);
+ void error(const Valgrind::XmlProtocol::Error &error);
+
+private:
+ QString runTestBinary(const QString &binary, const QStringList &vArgs = QStringList());
+
+ XmlProtocol::ThreadedParser *m_parser;
+ Memcheck::MemcheckRunner *m_runner;
+ QList<QByteArray> m_logMessages;
+ QList<XmlProtocol::Error> m_errors;
+ bool m_expectCrash;
+};
+
+} // namespace Valgrind
+
+#endif // TESTRUNNER_H
diff --git a/tests/valgrind/memcheck/testrunner.pro b/tests/valgrind/memcheck/testrunner.pro
new file mode 100644
index 0000000000..03af445198
--- /dev/null
+++ b/tests/valgrind/memcheck/testrunner.pro
@@ -0,0 +1,18 @@
+TEMPLATE = app
+TARGET = testrunner
+
+macx:CONFIG -= app_bundle
+
+QT += testlib network
+
+DEFINES += "TESTRUNNER_SRC_DIR=\"\\\"$$_PRO_FILE_PWD_/testapps\\\"\""
+DEFINES += "TESTRUNNER_APP_DIR=\"\\\"$(PWD)/testapps\\\"\""
+
+!win32 {
+ include(../../../qtcreator.pri)
+ include(../../../src/libs/valgrind/valgrind.pri)
+}
+
+SOURCES += testrunner.cpp
+
+HEADERS += testrunner.h
diff --git a/tests/valgrind/valgrind.pro b/tests/valgrind/valgrind.pro
new file mode 100644
index 0000000000..62bb9ec985
--- /dev/null
+++ b/tests/valgrind/valgrind.pro
@@ -0,0 +1,3 @@
+TEMPLATE = subdirs
+
+SUBDIRS += memcheck