forked from qt-creator/qt-creator
Add libvalgrind tests.
Merge-request: 260 Reviewed-by: hjk <qtc-committer@nokia.com>
This commit is contained in:
16
.gitignore
vendored
16
.gitignore
vendored
@@ -110,4 +110,18 @@ tests/auto/qml/qmldesigner/coretests/tst_qmldesigner_core
|
|||||||
tests/auto/qml/qmldesigner/propertyeditortests/tst_propertyeditor
|
tests/auto/qml/qmldesigner/propertyeditortests/tst_propertyeditor
|
||||||
tests/auto/profilewriter/tst_profilewriter
|
tests/auto/profilewriter/tst_profilewriter
|
||||||
tests/auto/externaltool/tst_externaltool
|
tests/auto/externaltool/tst_externaltool
|
||||||
|
tests/valgrind/memcheck/modeldemo
|
||||||
|
tests/valgrind/memcheck/parsertests
|
||||||
|
tests/valgrind/memcheck/testapps/free1/free1
|
||||||
|
tests/valgrind/memcheck/testapps/free2/free2
|
||||||
|
tests/valgrind/memcheck/testapps/invalidjump/invalidjump
|
||||||
|
tests/valgrind/memcheck/testapps/leak1/leak1
|
||||||
|
tests/valgrind/memcheck/testapps/leak2/leak2
|
||||||
|
tests/valgrind/memcheck/testapps/leak3/leak3
|
||||||
|
tests/valgrind/memcheck/testapps/leak4/leak4
|
||||||
|
tests/valgrind/memcheck/testapps/overlap/overlap
|
||||||
|
tests/valgrind/memcheck/testapps/syscall/syscall
|
||||||
|
tests/valgrind/memcheck/testapps/uninit1/uninit1
|
||||||
|
tests/valgrind/memcheck/testapps/uninit2/uninit2
|
||||||
|
tests/valgrind/memcheck/testapps/uninit3/uninit3
|
||||||
|
tests/valgrind/memcheck/testrunner
|
||||||
|
@@ -1,2 +1,5 @@
|
|||||||
TEMPLATE=subdirs
|
TEMPLATE=subdirs
|
||||||
SUBDIRS += auto manual tools
|
SUBDIRS += auto manual tools
|
||||||
|
!win32 {
|
||||||
|
SUBDIRS += valgrind
|
||||||
|
}
|
||||||
|
6
tests/valgrind/README
Normal file
6
tests/valgrind/README
Normal file
@@ -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
|
3
tests/valgrind/memcheck/memcheck.pro
Normal file
3
tests/valgrind/memcheck/memcheck.pro
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
TEMPLATE = subdirs
|
||||||
|
|
||||||
|
SUBDIRS += parsertests.pro modeldemo.pro testapps testrunner.pro
|
99
tests/valgrind/memcheck/modeldemo.cpp
Normal file
99
tests/valgrind/memcheck/modeldemo.cpp
Normal file
@@ -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();
|
||||||
|
}
|
80
tests/valgrind/memcheck/modeldemo.h
Normal file
80
tests/valgrind/memcheck/modeldemo.h
Normal file
@@ -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
|
17
tests/valgrind/memcheck/modeldemo.pro
Normal file
17
tests/valgrind/memcheck/modeldemo.pro
Normal file
@@ -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
|
508
tests/valgrind/memcheck/parsertests.cpp
Normal file
508
tests/valgrind/memcheck/parsertests.cpp
Normal file
@@ -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)
|
186
tests/valgrind/memcheck/parsertests.h
Normal file
186
tests/valgrind/memcheck/parsertests.h
Normal file
@@ -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
|
19
tests/valgrind/memcheck/parsertests.pro
Normal file
19
tests/valgrind/memcheck/parsertests.pro
Normal file
@@ -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
|
8
tests/valgrind/memcheck/testapps/free1/free1.pro
Normal file
8
tests/valgrind/memcheck/testapps/free1/free1.pro
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
TEMPLATE = app
|
||||||
|
TARGET = free1
|
||||||
|
|
||||||
|
QT -= core gui
|
||||||
|
|
||||||
|
macx:CONFIG -= app_bundle
|
||||||
|
|
||||||
|
SOURCES += main.cpp
|
9
tests/valgrind/memcheck/testapps/free1/main.cpp
Normal file
9
tests/valgrind/memcheck/testapps/free1/main.cpp
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
int *p = new int;
|
||||||
|
delete p;
|
||||||
|
delete p;
|
||||||
|
return 0;
|
||||||
|
}
|
8
tests/valgrind/memcheck/testapps/free2/free2.pro
Normal file
8
tests/valgrind/memcheck/testapps/free2/free2.pro
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
TEMPLATE = app
|
||||||
|
TARGET = free2
|
||||||
|
|
||||||
|
QT -= core gui
|
||||||
|
|
||||||
|
macx:CONFIG -= app_bundle
|
||||||
|
|
||||||
|
SOURCES += main.cpp
|
8
tests/valgrind/memcheck/testapps/free2/main.cpp
Normal file
8
tests/valgrind/memcheck/testapps/free2/main.cpp
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
int *p = new int;
|
||||||
|
free(p);
|
||||||
|
return 0;
|
||||||
|
}
|
@@ -0,0 +1,8 @@
|
|||||||
|
TEMPLATE = app
|
||||||
|
TARGET = invalidjump
|
||||||
|
|
||||||
|
QT -= core gui
|
||||||
|
|
||||||
|
macx:CONFIG -= app_bundle
|
||||||
|
|
||||||
|
SOURCES += main.cpp
|
8
tests/valgrind/memcheck/testapps/invalidjump/main.cpp
Normal file
8
tests/valgrind/memcheck/testapps/invalidjump/main.cpp
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
void foo() { }
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
void (*fooPtr)() = 0;
|
||||||
|
fooPtr();
|
||||||
|
return 0;
|
||||||
|
}
|
8
tests/valgrind/memcheck/testapps/leak1/leak1.pro
Normal file
8
tests/valgrind/memcheck/testapps/leak1/leak1.pro
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
TEMPLATE = app
|
||||||
|
TARGET = leak1
|
||||||
|
|
||||||
|
QT += core
|
||||||
|
|
||||||
|
macx:CONFIG -= app_bundle
|
||||||
|
|
||||||
|
SOURCES += main.cpp
|
7
tests/valgrind/memcheck/testapps/leak1/main.cpp
Normal file
7
tests/valgrind/memcheck/testapps/leak1/main.cpp
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
#include <qglobal.h>
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
qint64 *i = new qint64;
|
||||||
|
return 0;
|
||||||
|
}
|
8
tests/valgrind/memcheck/testapps/leak2/leak2.pro
Normal file
8
tests/valgrind/memcheck/testapps/leak2/leak2.pro
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
TEMPLATE = app
|
||||||
|
TARGET = leak2
|
||||||
|
|
||||||
|
QT += core
|
||||||
|
|
||||||
|
macx:CONFIG -= app_bundle
|
||||||
|
|
||||||
|
SOURCES += main.cpp
|
13
tests/valgrind/memcheck/testapps/leak2/main.cpp
Normal file
13
tests/valgrind/memcheck/testapps/leak2/main.cpp
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
char *lower;
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
lower = strdup("asdf");
|
||||||
|
|
||||||
|
while (*lower)
|
||||||
|
*(lower++);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
8
tests/valgrind/memcheck/testapps/leak3/leak3.pro
Normal file
8
tests/valgrind/memcheck/testapps/leak3/leak3.pro
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
TEMPLATE = app
|
||||||
|
TARGET = leak3
|
||||||
|
|
||||||
|
QT += core
|
||||||
|
|
||||||
|
macx:CONFIG -= app_bundle
|
||||||
|
|
||||||
|
SOURCES += main.cpp
|
10
tests/valgrind/memcheck/testapps/leak3/main.cpp
Normal file
10
tests/valgrind/memcheck/testapps/leak3/main.cpp
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
char *lower;
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
lower = strdup("asdf");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
8
tests/valgrind/memcheck/testapps/leak4/leak4.pro
Normal file
8
tests/valgrind/memcheck/testapps/leak4/leak4.pro
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
TEMPLATE = app
|
||||||
|
TARGET = leak4
|
||||||
|
|
||||||
|
QT += core
|
||||||
|
|
||||||
|
macx:CONFIG -= app_bundle
|
||||||
|
|
||||||
|
SOURCES += main.cpp
|
17
tests/valgrind/memcheck/testapps/leak4/main.cpp
Normal file
17
tests/valgrind/memcheck/testapps/leak4/main.cpp
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
#include <qglobal.h>
|
||||||
|
|
||||||
|
struct Foo
|
||||||
|
{
|
||||||
|
Foo()
|
||||||
|
: num(new qint64)
|
||||||
|
{}
|
||||||
|
|
||||||
|
qint64 *num;
|
||||||
|
};
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
Foo *f = new Foo;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
9
tests/valgrind/memcheck/testapps/overlap/main.cpp
Normal file
9
tests/valgrind/memcheck/testapps/overlap/main.cpp
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
int *i = new int[10];
|
||||||
|
memcpy(i, &i[1], 20);
|
||||||
|
delete[] i;
|
||||||
|
return 0;
|
||||||
|
}
|
8
tests/valgrind/memcheck/testapps/overlap/overlap.pro
Normal file
8
tests/valgrind/memcheck/testapps/overlap/overlap.pro
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
TEMPLATE = app
|
||||||
|
TARGET = overlap
|
||||||
|
|
||||||
|
QT -= core gui
|
||||||
|
|
||||||
|
macx:CONFIG -= app_bundle
|
||||||
|
|
||||||
|
SOURCES += main.cpp
|
5
tests/valgrind/memcheck/testapps/syscall/main.cpp
Normal file
5
tests/valgrind/memcheck/testapps/syscall/main.cpp
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
int main()
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
return i;
|
||||||
|
}
|
8
tests/valgrind/memcheck/testapps/syscall/syscall.pro
Normal file
8
tests/valgrind/memcheck/testapps/syscall/syscall.pro
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
TEMPLATE = app
|
||||||
|
TARGET = syscall
|
||||||
|
|
||||||
|
QT += core
|
||||||
|
|
||||||
|
macx:CONFIG -= app_bundle
|
||||||
|
|
||||||
|
SOURCES += main.cpp
|
4
tests/valgrind/memcheck/testapps/testapps.pro
Normal file
4
tests/valgrind/memcheck/testapps/testapps.pro
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
TEMPLATE = subdirs
|
||||||
|
|
||||||
|
SUBDIRS += leak1 leak2 leak3 leak4 uninit1 uninit2 syscall free1 uninit3 free2 invalidjump \
|
||||||
|
overlap
|
9
tests/valgrind/memcheck/testapps/uninit1/main.cpp
Normal file
9
tests/valgrind/memcheck/testapps/uninit1/main.cpp
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
int main()
|
||||||
|
{
|
||||||
|
bool b;
|
||||||
|
if (b) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
8
tests/valgrind/memcheck/testapps/uninit1/uninit1.pro
Normal file
8
tests/valgrind/memcheck/testapps/uninit1/uninit1.pro
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
TEMPLATE = app
|
||||||
|
TARGET = uninit1
|
||||||
|
|
||||||
|
QT += core
|
||||||
|
|
||||||
|
macx:CONFIG -= app_bundle
|
||||||
|
|
||||||
|
SOURCES += main.cpp
|
7
tests/valgrind/memcheck/testapps/uninit2/main.cpp
Normal file
7
tests/valgrind/memcheck/testapps/uninit2/main.cpp
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
int main()
|
||||||
|
{
|
||||||
|
int *i;
|
||||||
|
*i = 5;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
8
tests/valgrind/memcheck/testapps/uninit2/uninit2.pro
Normal file
8
tests/valgrind/memcheck/testapps/uninit2/uninit2.pro
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
TEMPLATE = app
|
||||||
|
TARGET = uninit2
|
||||||
|
|
||||||
|
QT -= core gui
|
||||||
|
|
||||||
|
macx:CONFIG -= app_bundle
|
||||||
|
|
||||||
|
SOURCES += main.cpp
|
5
tests/valgrind/memcheck/testapps/uninit3/main.cpp
Normal file
5
tests/valgrind/memcheck/testapps/uninit3/main.cpp
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
int main()
|
||||||
|
{
|
||||||
|
int *i;
|
||||||
|
return *i;
|
||||||
|
}
|
8
tests/valgrind/memcheck/testapps/uninit3/uninit3.pro
Normal file
8
tests/valgrind/memcheck/testapps/uninit3/uninit3.pro
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
TEMPLATE = app
|
||||||
|
TARGET = uninit3
|
||||||
|
|
||||||
|
QT -= core gui
|
||||||
|
|
||||||
|
macx:CONFIG -= app_bundle
|
||||||
|
|
||||||
|
SOURCES += main.cpp
|
703
tests/valgrind/memcheck/testrunner.cpp
Normal file
703
tests/valgrind/memcheck/testrunner.cpp
Normal file
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
98
tests/valgrind/memcheck/testrunner.h
Normal file
98
tests/valgrind/memcheck/testrunner.h
Normal file
@@ -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
|
18
tests/valgrind/memcheck/testrunner.pro
Normal file
18
tests/valgrind/memcheck/testrunner.pro
Normal file
@@ -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
|
3
tests/valgrind/valgrind.pro
Normal file
3
tests/valgrind/valgrind.pro
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
TEMPLATE = subdirs
|
||||||
|
|
||||||
|
SUBDIRS += memcheck
|
Reference in New Issue
Block a user