Merge remote-tracking branch 'origin/4.2'

Conflicts:
	qbs/modules/qtc/qtc.qbs
	qtcreator.pri
	src/plugins/projectexplorer/kitinformation.cpp

Change-Id: I94299b069418586db97d1d596a252794e4037556
This commit is contained in:
Eike Ziller
2016-12-20 17:14:19 +01:00
61 changed files with 1032 additions and 1621 deletions

View File

@@ -0,0 +1,370 @@
<?xml version="1.0"?>
<valgrindoutput>
<protocolversion>4</protocolversion>
<protocoltool>memcheck</protocoltool>
<preamble>
<line>Memcheck, a memory error detector</line>
<line>Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.</line>
<line>Using Valgrind-3.6.0.SVN-Debian and LibVEX; rerun with -h for copyright info</line>
<line>Command: kate</line>
</preamble>
<pid>22733</pid>
<ppid>17584</ppid>
<tool>memcheck</tool>
<args>
<vargv>
<exe>/usr/bin/valgrind.bin</exe>
<arg>--suppressions=/usr/lib/valgrind/debian-libc6-dbg.supp</arg>
<arg>--xml=yes</arg>
<arg>--xml-file=test.xml</arg>
<arg>--track-origins=yes</arg>
</vargv>
<argv>
<exe>kate</exe>
</argv>
</args>
<status>
<state>RUNNING</state>
<time>00:00:00:00.241 </time>
</status>
<error>
<unique>0x9</unique>
<tid>1</tid>
<kind>InvalidRead</kind>
<what>Invalid read of size 4</what>
<stack>
<frame>
<ip>0x6E47964</ip>
<obj>/usr/lib/libQtGui.so.4.7.0</obj>
<fn>QFrame::frameStyle() const</fn>
<dir>/build/buildd/qt4-x11-4.7.0/src/gui/widgets</dir>
<file>qframe.cpp</file>
<line>252</line>
</frame>
<frame>
<ip>0x118F2AF7</ip>
<obj>/usr/lib/kde4/plugins/styles/oxygen.so</obj>
</frame>
<frame>
<ip>0x6A81671</ip>
<obj>/usr/lib/libQtGui.so.4.7.0</obj>
<fn>QWidget::event(QEvent*)</fn>
<dir>/build/buildd/qt4-x11-4.7.0/src/gui/kernel</dir>
<file>qwidget.cpp</file>
<line>8273</line>
</frame>
<frame>
<ip>0x6A2B6EB</ip>
<obj>/usr/lib/libQtGui.so.4.7.0</obj>
<fn>QApplicationPrivate::notify_helper(QObject*, QEvent*)</fn>
<dir>/build/buildd/qt4-x11-4.7.0/src/gui/kernel</dir>
<file>qapplication.cpp</file>
<line>4396</line>
</frame>
<!--
<frame>
<ip>0x6A311DC</ip>
<obj>/usr/lib/libQtGui.so.4.7.0</obj>
<fn>QApplication::notify(QObject*, QEvent*)</fn>
<dir>/build/buildd/qt4-x11-4.7.0/src/gui/kernel</dir>
<file>qapplication.cpp</file>
<line>4277</line>
</frame>
<frame>
<ip>0x6443535</ip>
<obj>/usr/lib/libkdeui.so.5.5.0</obj>
<fn>KApplication::notify(QObject*, QEvent*)</fn>
</frame>
<frame>
<ip>0x83690AB</ip>
<obj>/usr/lib/libQtCore.so.4.7.0</obj>
<fn>QCoreApplication::notifyInternal(QObject*, QEvent*)</fn>
<dir>/build/buildd/qt4-x11-4.7.0/src/corelib/kernel</dir>
<file>qcoreapplication.cpp</file>
<line>732</line>
</frame>
<frame>
<ip>0x6A77600</ip>
<obj>/usr/lib/libQtGui.so.4.7.0</obj>
<fn>QWidget::ensurePolished() const</fn>
<dir>/build/buildd/qt4-x11-4.7.0/src/gui/../../include/QtCore/../../src/corelib/kernel</dir>
<file>qcoreapplication.h</file>
<line>215</line>
</frame>
<frame>
<ip>0x6A869B2</ip>
<obj>/usr/lib/libQtGui.so.4.7.0</obj>
<fn>QWidget::setVisible(bool)</fn>
<dir>/build/buildd/qt4-x11-4.7.0/src/gui/kernel</dir>
<file>qwidget.cpp</file>
<line>7539</line>
</frame>
<frame>
<ip>0x18B1ED35</ip>
<obj>/home/milian/projects/compiled/kde4/lib/libkatepartinterfaces.so.4.5.0</obj>
<fn>QWidget::show()</fn>
<dir>/usr/include/qt4/QtGui</dir>
<file>qwidget.h</file>
<line>487</line>
</frame>
<frame>
<ip>0x18C23615</ip>
<obj>/home/milian/projects/compiled/kde4/lib/libkatepartinterfaces.so.4.5.0</obj>
<fn>KateViewInternal::KateViewInternal(KateView*)</fn>
<dir>/home/milian/projects/kde4/kate/part/view</dir>
<file>kateviewinternal.cpp</file>
<line>144</line>
</frame>
<frame>
<ip>0x18C0DA68</ip>
<obj>/home/milian/projects/compiled/kde4/lib/libkatepartinterfaces.so.4.5.0</obj>
<fn>KateView::KateView(KateDocument*, QWidget*)</fn>
<dir>/home/milian/projects/kde4/kate/part/view</dir>
<file>kateview.cpp</file>
<line>136</line>
</frame>
-->
</stack>
<auxwhat>Address 0x11527cb8 is not stack'd, malloc'd or (recently) free'd</auxwhat>
</error>
<status>
<state>FINISHED</state>
<time>00:00:01:49.732 </time>
</status>
<error>
<unique>0x13</unique>
<tid>1</tid>
<kind>Leak_PossiblyLost</kind>
<xwhat>
<text>2 bytes in 1 blocks are possibly lost in loss record 2 of 2,003</text>
<leakedbytes>2</leakedbytes>
<leakedblocks>1</leakedblocks>
</xwhat>
<stack>
<frame>
<ip>0x4C284A8</ip>
<obj>/usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so</obj>
<fn>malloc</fn>
<dir>/build/buildd/valgrind-3.6.0~svn20100212/coregrind/m_replacemalloc</dir>
<file>vg_replace_malloc.c</file>
<line>236</line>
</frame>
<frame>
<ip>0xD4D7754</ip>
<obj>/lib/libglib-2.0.so.0.2400.1</obj>
<fn>g_malloc</fn>
</frame>
<frame>
<ip>0xD4EF11D</ip>
<obj>/lib/libglib-2.0.so.0.2400.1</obj>
<fn>g_strdup</fn>
</frame>
<frame>
<ip>0xD503DC4</ip>
<obj>/lib/libglib-2.0.so.0.2400.1</obj>
<fn>g_get_language_names</fn>
</frame>
<frame>
<ip>0xD4F89A9</ip>
<obj>/lib/libglib-2.0.so.0.2400.1</obj>
<fn>g_thread_init_glib</fn>
</frame>
<frame>
<ip>0x8396569</ip>
<obj>/usr/lib/libQtCore.so.4.7.0</obj>
<fn>QEventDispatcherGlibPrivate::QEventDispatcherGlibPrivate(_GMainContext*)</fn>
<dir>/build/buildd/qt4-x11-4.7.0/src/corelib/kernel</dir>
<file>qeventdispatcher_glib.cpp</file>
<line>299</line>
</frame>
<frame>
<ip>0x6ADDBEE</ip>
<obj>/usr/lib/libQtGui.so.4.7.0</obj>
<fn>QGuiEventDispatcherGlibPrivate::QGuiEventDispatcherGlibPrivate()</fn>
<dir>/build/buildd/qt4-x11-4.7.0/src/gui/kernel</dir>
<file>qguieventdispatcher_glib.cpp</file>
<line>171</line>
</frame>
<frame>
<ip>0x6ADDCDD</ip>
<obj>/usr/lib/libQtGui.so.4.7.0</obj>
<fn>QGuiEventDispatcherGlib::QGuiEventDispatcherGlib(QObject*)</fn>
<dir>/build/buildd/qt4-x11-4.7.0/src/gui/kernel</dir>
<file>qguieventdispatcher_glib.cpp</file>
<line>186</line>
</frame>
<frame>
<ip>0x6AA5152</ip>
<obj>/usr/lib/libQtGui.so.4.7.0</obj>
<fn>QApplicationPrivate::createEventDispatcher()</fn>
<dir>/build/buildd/qt4-x11-4.7.0/src/gui/kernel</dir>
<file>qapplication_x11.cpp</file>
<line>605</line>
</frame>
<frame>
<ip>0x836D069</ip>
<obj>/usr/lib/libQtCore.so.4.7.0</obj>
<fn>QCoreApplication::init()</fn>
<dir>/build/buildd/qt4-x11-4.7.0/src/corelib/kernel</dir>
<file>qcoreapplication.cpp</file>
<line>552</line>
</frame>
<frame>
<ip>0x836D134</ip>
<obj>/usr/lib/libQtCore.so.4.7.0</obj>
<fn>QCoreApplication::QCoreApplication(QCoreApplicationPrivate&amp;)</fn>
<dir>/build/buildd/qt4-x11-4.7.0/src/corelib/kernel</dir>
<file>qcoreapplication.cpp</file>
<line>477</line>
</frame>
<frame>
<ip>0x6A3815A</ip>
<obj>/usr/lib/libQtGui.so.4.7.0</obj>
<fn>QApplication::QApplication(int&amp;, char**, bool, int)</fn>
<dir>/build/buildd/qt4-x11-4.7.0/src/gui/kernel</dir>
<file>qapplication.cpp</file>
<line>745</line>
</frame>
</stack>
</error>
<error>
<unique>0x7e4</unique>
<tid>1</tid>
<kind>Leak_DefinitelyLost</kind>
<xwhat>
<text>544,542 (56 direct, 544,486 indirect) bytes in 1 blocks are definitely lost in loss record 2,003 of 2,003</text>
<leakedbytes>544542</leakedbytes>
<leakedblocks>1</leakedblocks>
</xwhat>
<stack>
<frame>
<ip>0x4C284A8</ip>
<obj>/usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so</obj>
<fn>malloc</fn>
<dir>/build/buildd/valgrind-3.6.0~svn20100212/coregrind/m_replacemalloc</dir>
<file>vg_replace_malloc.c</file>
<line>236</line>
</frame>
<frame>
<ip>0x82A1A6C</ip>
<obj>/usr/lib/libQtCore.so.4.7.0</obj>
<fn>QMapData::node_create(QMapData::Node**, int, int)</fn>
<dir>/build/buildd/qt4-x11-4.7.0/src/corelib/tools</dir>
<file>qmap.cpp</file>
<line>140</line>
</frame>
<frame>
<ip>0x8336F68</ip>
<obj>/usr/lib/libQtCore.so.4.7.0</obj>
<fn>QMap&lt;QSettingsKey, QVariant&gt;::detach_helper()</fn>
<dir>/build/buildd/qt4-x11-4.7.0/src/corelib/../../include/QtCore/../../src/corelib/tools</dir>
<file>qmap.h</file>
<line>449</line>
</frame>
<frame>
<ip>0x832C564</ip>
<obj>/usr/lib/libQtCore.so.4.7.0</obj>
<fn>QConfFile::mergedKeyMap() const</fn>
<dir>/build/buildd/qt4-x11-4.7.0/src/corelib/../../include/QtCore/../../src/corelib/tools</dir>
<file>qmap.h</file>
<line>202</line>
</frame>
<frame>
<ip>0x833305A</ip>
<obj>/usr/lib/libQtCore.so.4.7.0</obj>
<fn>QConfFileSettingsPrivate::syncConfFile(int)</fn>
<dir>/build/buildd/qt4-x11-4.7.0/src/corelib/io</dir>
<file>qsettings.cpp</file>
<line>1569</line>
</frame>
<frame>
<ip>0x8333D5B</ip>
<obj>/usr/lib/libQtCore.so.4.7.0</obj>
<fn>QConfFileSettingsPrivate::sync()</fn>
<dir>/build/buildd/qt4-x11-4.7.0/src/corelib/io</dir>
<file>qsettings.cpp</file>
<line>1386</line>
</frame>
<frame>
<ip>0x83260D9</ip>
<obj>/usr/lib/libQtCore.so.4.7.0</obj>
<fn>QSettingsPrivate::update()</fn>
<dir>/build/buildd/qt4-x11-4.7.0/src/corelib/io</dir>
<file>qsettings.cpp</file>
<line>415</line>
</frame>
<frame>
<ip>0x83267C7</ip>
<obj>/usr/lib/libQtCore.so.4.7.0</obj>
<fn>QSettings::event(QEvent*)</fn>
<dir>/build/buildd/qt4-x11-4.7.0/src/corelib/io</dir>
<file>qsettings.cpp</file>
<line>3326</line>
</frame>
<frame>
<ip>0x6A2B6EB</ip>
<obj>/usr/lib/libQtGui.so.4.7.0</obj>
<fn>QApplicationPrivate::notify_helper(QObject*, QEvent*)</fn>
<dir>/build/buildd/qt4-x11-4.7.0/src/gui/kernel</dir>
<file>qapplication.cpp</file>
<line>4396</line>
</frame>
<frame>
<ip>0x6A311DC</ip>
<obj>/usr/lib/libQtGui.so.4.7.0</obj>
<fn>QApplication::notify(QObject*, QEvent*)</fn>
<dir>/build/buildd/qt4-x11-4.7.0/src/gui/kernel</dir>
<file>qapplication.cpp</file>
<line>4277</line>
</frame>
<frame>
<ip>0x6443535</ip>
<obj>/usr/lib/libkdeui.so.5.5.0</obj>
<fn>KApplication::notify(QObject*, QEvent*)</fn>
</frame>
<frame>
<ip>0x83690AB</ip>
<obj>/usr/lib/libQtCore.so.4.7.0</obj>
<fn>QCoreApplication::notifyInternal(QObject*, QEvent*)</fn>
<dir>/build/buildd/qt4-x11-4.7.0/src/corelib/kernel</dir>
<file>qcoreapplication.cpp</file>
<line>732</line>
</frame>
</stack>
</error>
<errorcounts>
<pair>
<count>2</count>
<unique>0x9</unique>
</pair>
</errorcounts>
<suppcounts>
<pair>
<count>12</count>
<name>X on SUSE11 writev uninit padding</name>
</pair>
<pair>
<count>2</count>
<name>dl-hack3-cond-1</name>
</pair>
<pair>
<count>2</count>
<name>glibc-2.5.x-on-SUSE-10.2-(PPC)-2a</name>
</pair>
</suppcounts>
</valgrindoutput>

View File

@@ -55,3 +55,16 @@ FORMS += \
RESOURCES += \
valgrind.qrc
equals(TEST, 1) {
DEFINES += "PARSERTESTS_DATA_DIR=\\\"$$_PRO_FILE_PWD_/unit_testdata\\\""
DEFINES += "VALGRIND_FAKE_PATH=\\\"$$IDE_BUILD_TREE/src/tools/valgrindfake\\\""
DEFINES += "TESTRUNNER_SRC_DIR=\\\"$$_PRO_FILE_PWD_/../../../tests/auto/valgrind/memcheck/testapps\\\""
DEFINES += "TESTRUNNER_APP_DIR=\\\"$(PWD)/../../../tests/auto/valgrind/memcheck/testapps\\\""
HEADERS += valgrindmemcheckparsertest.h \
valgrindtestrunnertest.h
SOURCES += valgrindmemcheckparsertest.cpp \
valgrindtestrunnertest.cpp
}

View File

@@ -1,4 +1,5 @@
import qbs 1.0
import qbs
import qbs.FileInfo
QtcPlugin {
name: "Valgrind"
@@ -88,4 +89,21 @@ QtcPlugin {
"threadedparser.cpp", "threadedparser.h",
]
}
Group {
name: "Test sources"
condition: qtc.testsEnabled
files: [
"valgrindmemcheckparsertest.cpp",
"valgrindmemcheckparsertest.h",
"valgrindtestrunnertest.cpp",
"valgrindtestrunnertest.h",
]
cpp.defines: outer.concat([
'PARSERTESTS_DATA_DIR="' + FileInfo.joinPaths(path, "unit_testdata") + '"',
'VALGRIND_FAKE_PATH="' + FileInfo.joinPaths(project.buildDirectory, qtc.ide_bin_path) + '"',
'TESTRUNNER_SRC_DIR="' + FileInfo.joinPaths(path, "../../../tests/auto/valgrind/memcheck/testapps") + '"',
'TESTRUNNER_APP_DIR="' + FileInfo.joinPaths(project.buildDirectory, qtc.ide_bin_path, "testapps") + '"'
])
}
}

View File

@@ -0,0 +1,547 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Author: Frank Osterfeld, KDAB (frank.osterfeld@kdab.com)
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "valgrindmemcheckparsertest.h"
#include "xmlprotocol/frame.h"
#include "xmlprotocol/parser.h"
#include "xmlprotocol/stack.h"
#include "xmlprotocol/suppression.h"
#include <projectexplorer/devicesupport/devicemanager.h>
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/runnables.h>
#include <QFile>
#include <QFileInfo>
#include <QProcess>
#include <QString>
#include <QTest>
#include <QTcpServer>
#include <QTcpSocket>
#include <QSignalSpy>
using namespace Valgrind::XmlProtocol;
QT_BEGIN_NAMESPACE
namespace QTest {
template<>
inline bool qCompare(int const &t1, 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
namespace Valgrind {
namespace Test {
static void dumpFrame(const Frame &f)
{
qDebug() << f.instructionPointer() << f.directory() << f.fileName() << 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();
for (const Stack &s : e.stacks()) {
qDebug() << s.auxWhat() << s.directory() << s.file() << s.line() << s.helgrindThreadId();
qDebug() << "frames:";
for (const Frame &f : s.frames()) {
dumpFrame(f);
}
}
}
static QString fakeValgrindExecutable()
{
QString valgrindFakePath(VALGRIND_FAKE_PATH);
if (Utils::HostOsInfo::isWindowsHost()) {
QFileInfo fi(QString(valgrindFakePath + "/debug"), "valgrind-fake.exe");
if (fi.exists())
return fi.canonicalFilePath();
fi = QFileInfo(QString(valgrindFakePath + "/release"), "valgrind-fake.exe");
if (fi.exists())
return fi.canonicalFilePath();
// Qbs uses the install-root/bin
fi = QFileInfo(valgrindFakePath, "valgrind-fake.exe");
if (fi.exists())
return fi.canonicalFilePath();
qFatal("Neither debug nor release build valgrind-fake found.");
}
return valgrindFakePath + "/valgrind-fake";
}
static QString dataFile(const QLatin1String &file)
{
return QLatin1String(PARSERTESTS_DATA_DIR) + QLatin1String("/") + file;
}
void ValgrindMemcheckParserTest::initTestCase()
{
m_server = new QTcpServer(this);
QVERIFY(m_server->listen());
m_socket = 0;
m_process = 0;
}
void ValgrindMemcheckParserTest::initTest(const QLatin1String &testfile, const QStringList &otherArgs)
{
QVERIFY(!m_server->hasPendingConnections());
m_process = new QProcess(m_server);
m_process->setProcessChannelMode(QProcess::ForwardedChannels);
const QString fakeValgrind = fakeValgrindExecutable();
QFileInfo fileInfo(fakeValgrind);
QVERIFY2(fileInfo.isExecutable(), qPrintable(fakeValgrind));
QVERIFY2(!fileInfo.isDir(), qPrintable(fakeValgrind));
m_process->start(
fakeValgrind,
QStringList()
<< QString::fromLatin1("--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 ValgrindMemcheckParserTest::cleanup()
{
if (m_socket) {
delete m_socket;
m_socket = 0;
}
if (m_process) {
delete m_process;
m_process = 0;
}
}
void ValgrindMemcheckParserTest::testHelgrindSample1()
{
QSKIP("testfile does not exist");
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.setFileName(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.setFileName(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.setFileName(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.setFileName(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.setFileName(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.setFileName(QLatin1String("qmutex.h"));
frame32.setLine(122);
stack3.setFrames(QVector<Frame>() << frame31 << frame32);
error1.setStacks(QVector<Stack>() << stack1 << stack2 << stack3);
expectedErrors.append(error1);
}
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 ValgrindMemcheckParserTest::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.setFileName(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.setFileName(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.setFileName(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)));
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 ValgrindMemcheckParserTest::testMemcheckSample2()
{
QSKIP("testfile does not exist");
initTest(QLatin1String("memcheck-output-sample2.xml"));
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 ValgrindMemcheckParserTest::testMemcheckSample3()
{
QSKIP("testfile does not exist");
initTest(QLatin1String("memcheck-output-sample3.xml"));
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 ValgrindMemcheckParserTest::testMemcheckCharm()
{
QSKIP("testfile does not exist");
// a somewhat larger file, to make sure buffering and partial I/O works ok
initTest(QLatin1String("memcheck-output-untitled.xml"));
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 ValgrindMemcheckParserTest::testValgrindCrash()
{
initTest(QLatin1String("memcheck-output-sample1.xml"), QStringList() << "--crash");
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 ValgrindMemcheckParserTest::testValgrindGarbage()
{
initTest(QLatin1String("memcheck-output-sample1.xml"), QStringList() << "--garbage");
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 ValgrindMemcheckParserTest::testParserStop()
{
ThreadedParser parser;
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.setDevice(ProjectExplorer::DeviceManager::instance()->defaultDevice(
Core::Id(ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE)));
runner.start();
QTest::qWait(500);
runner.stop();
}
void ValgrindMemcheckParserTest::testRealValgrind()
{
const Utils::Environment &sysEnv = Utils::Environment::systemEnvironment();
auto fileName = sysEnv.searchInPath("valgrind");
if (fileName.isEmpty())
QSKIP("This test needs valgrind in PATH");
QString executable = QProcessEnvironment::systemEnvironment().value("VALGRIND_TEST_BIN", fakeValgrindExecutable());
qDebug() << "running exe:" << executable << " HINT: set VALGRIND_TEST_BIN to change this";
ThreadedParser parser;
ProjectExplorer::StandardRunnable debuggee;
debuggee.executable = executable;
debuggee.environment = sysEnv;
Memcheck::MemcheckRunner runner;
runner.setValgrindExecutable(QLatin1String("valgrind"));
runner.setDebuggee(debuggee);
runner.setDevice(ProjectExplorer::DeviceManager::instance()->defaultDevice(
Core::Id(ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE)));
runner.setParser(&parser);
RunnerDumper dumper(&runner, &parser);
runner.start();
runner.waitForFinished();
}
void ValgrindMemcheckParserTest::testValgrindStartError_data()
{
QTest::addColumn<QString>("valgrindExe");
QTest::addColumn<QStringList>("valgrindArgs");
QTest::addColumn<QString>("debuggee");
QTest::addColumn<QString>("debuggeeArgs");
QTest::newRow("invalid_client") << QString::fromLatin1("valgrind") << QStringList()
<< QString::fromLatin1("please-dont-let-this-app-exist") << QString();
QTest::newRow("invalid_valgrind") << QString::fromLatin1("valgrind-that-does-not-exist") << QStringList()
<< fakeValgrindExecutable() << QString();
QTest::newRow("invalid_valgrind_args") << QString::fromLatin1("valgrind")
<< (QStringList() << QString::fromLatin1("--foobar-fail"))
<< fakeValgrindExecutable() << QString();
}
void ValgrindMemcheckParserTest::testValgrindStartError()
{
QFETCH(QString, valgrindExe);
QFETCH(QStringList, valgrindArgs);
QFETCH(QString, debuggee);
QFETCH(QString, debuggeeArgs);
ThreadedParser parser;
ProjectExplorer::StandardRunnable debuggeeExecutable;
debuggeeExecutable.executable = debuggee;
debuggeeExecutable.environment = Utils::Environment::systemEnvironment();
debuggeeExecutable.commandLineArguments = debuggeeArgs;
Memcheck::MemcheckRunner runner;
runner.setParser(&parser);
runner.setValgrindExecutable(valgrindExe);
runner.setValgrindArguments(valgrindArgs);
runner.setDebuggee(debuggeeExecutable);
runner.setDevice(ProjectExplorer::DeviceManager::instance()->defaultDevice(
Core::Id(ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE)));
RunnerDumper dumper(&runner, &parser);
runner.start();
runner.waitForFinished();
QVERIFY(dumper.m_errorReceived);
// just finish without deadlock and we are fine
}
} // namespace Test
} // namespace Valgrind

View File

@@ -0,0 +1,172 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Author: Frank Osterfeld, KDAB (frank.osterfeld@kdab.com)
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <QObject>
#include <QPair>
#include <QStringList>
#include <QVector>
#include <QDebug>
#include "xmlprotocol/error.h"
#include "xmlprotocol/status.h"
#include "xmlprotocol/threadedparser.h"
#include "xmlprotocol/parser.h"
#include "memcheck/memcheckrunner.h"
QT_BEGIN_NAMESPACE
class QTcpServer;
class QTcpSocket;
class QProcess;
QT_END_NAMESPACE
namespace Valgrind {
namespace Test {
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, &Valgrind::XmlProtocol::Parser::error,
this, &Recorder::error);
connect(parser, &Valgrind::XmlProtocol::Parser::errorCount,
this, &Recorder::errorCount);
connect(parser, &Valgrind::XmlProtocol::Parser::suppressionCount,
this, &Recorder::suppressionCount);
}
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 unique, qint64 count)
{
errorcounts.push_back(qMakePair(unique, 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, &Valgrind::XmlProtocol::ThreadedParser::error,
this, &RunnerDumper::error);
connect(parser, &Valgrind::XmlProtocol::ThreadedParser::internalError,
this, &RunnerDumper::internalError);
connect(parser, &Valgrind::XmlProtocol::ThreadedParser::status,
this, &RunnerDumper::status);
connect(runner, &Valgrind::Memcheck::MemcheckRunner::logMessageReceived,
this, &RunnerDumper::logMessageReceived);
connect(runner, &Valgrind::ValgrindRunner::processErrorReceived,
this, &RunnerDumper::processErrorReceived);
}
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 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 ValgrindMemcheckParserTest : 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 = 0;
QProcess *m_process = 0;
QTcpSocket *m_socket = 0;
};
} // namespace Test
} // namespace Valgrind

View File

@@ -32,6 +32,11 @@
#include "valgrindsettings.h"
#include "valgrindconfigwidget.h"
#ifdef WITH_TESTS
# include "valgrindmemcheckparsertest.h"
# include "valgrindtestrunnertest.h"
#endif
#include <coreplugin/dialogs/ioptionspage.h>
#include <coreplugin/icontext.h>
#include <coreplugin/icore.h>
@@ -117,5 +122,14 @@ ValgrindGlobalSettings *ValgrindPlugin::globalSettings()
return theGlobalSettings;
}
QList<QObject *> ValgrindPlugin::createTestObjects() const
{
QList<QObject *> tests;
#ifdef WITH_TESTS
tests << new Test::ValgrindMemcheckParserTest << new Test::ValgrindTestRunnerTest;
#endif
return tests;
}
} // namespace Internal
} // namespace Valgrind

View File

@@ -48,6 +48,8 @@ public:
ShutdownFlag aboutToShutdown() override;
static ValgrindGlobalSettings *globalSettings();
private:
QList<QObject *> createTestObjects() const override;
};
} // namespace Internal

View File

@@ -0,0 +1,775 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Author: Milian Wolff, KDAB (milian.wolff@kdab.com)
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "valgrindtestrunnertest.h"
#include "xmlprotocol/frame.h"
#include "xmlprotocol/stack.h"
#include "xmlprotocol/suppression.h"
#include "xmlprotocol/threadedparser.h"
#include "xmlprotocol/parser.h"
#include "memcheck/memcheckrunner.h"
#include <projectexplorer/devicesupport/devicemanager.h>
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/runnables.h>
#include <QDebug>
#include <QTest>
#include <QDir>
#include <QSignalSpy>
#define HEADER_LENGTH 25
using namespace Valgrind::XmlProtocol;
using namespace Valgrind::Memcheck;
namespace Valgrind {
namespace Test {
//BEGIN Test Helpers and boilerplate code
static const QString appSrcDir(TESTRUNNER_SRC_DIR);
static const QString appBinDir(TESTRUNNER_APP_DIR);
static bool on64bit()
{
return sizeof(char*) == 8;
}
static QString srcDirForApp(const QString &app)
{
return QDir::cleanPath(appSrcDir + QLatin1Char('/') + app);
}
ValgrindTestRunnerTest::ValgrindTestRunnerTest(QObject *parent)
: QObject(parent)
{
qRegisterMetaType<Error>();
}
QString ValgrindTestRunnerTest::runTestBinary(const QString &binary, const QStringList &vArgs)
{
const QFileInfo binPathFileInfo(appBinDir, binary);
if (!binPathFileInfo.isExecutable())
return QString();
ProjectExplorer::StandardRunnable debuggee;
const QString &binPath = binPathFileInfo.canonicalFilePath();
debuggee.executable = binPath;
debuggee.environment = Utils::Environment::systemEnvironment();
m_runner->setValgrindArguments(QStringList() << "--num-callers=50" << "--track-origins=yes" << vArgs);
m_runner->setDebuggee(debuggee);
m_runner->setDevice(ProjectExplorer::DeviceManager::instance()->defaultDevice(
Core::Id(ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE)));
m_runner->start();
m_runner->waitForFinished();
return binPath;
}
void ValgrindTestRunnerTest::logMessageReceived(const QByteArray &message)
{
qDebug() << "log message received:" << message;
m_logMessages << message;
}
void ValgrindTestRunnerTest::internalError(const QString &error)
{
if (!m_expectCrash)
QFAIL(qPrintable(error));
else
qDebug() << "expected crash:" << error;
}
void ValgrindTestRunnerTest::error(const Error &error)
{
m_errors << error;
}
void ValgrindTestRunnerTest::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 ValgrindTestRunnerTest::init()
{
const Utils::Environment &sysEnv = Utils::Environment::systemEnvironment();
auto fileName = sysEnv.searchInPath("valgrind");
if (fileName.isEmpty())
QSKIP("This test needs valgrind in PATH");
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, &MemcheckRunner::logMessageReceived,
this, &ValgrindTestRunnerTest::logMessageReceived);
connect(m_runner, &ValgrindRunner::processErrorReceived,
this, &ValgrindTestRunnerTest::internalError);
Q_ASSERT(!m_parser);
m_parser = new ThreadedParser;
connect(m_parser, &ThreadedParser::internalError,
this, &ValgrindTestRunnerTest::internalError);
connect(m_parser, &ThreadedParser::error,
this, &ValgrindTestRunnerTest::error);
m_runner->setParser(m_parser);
}
//BEGIN: Actual test cases
void ValgrindTestRunnerTest::testLeak1()
{
const QString binary = runTestBinary(QLatin1String("leak1/leak1"));
if (binary.isEmpty())
QSKIP("You need to pass BUILD_TESTS when building Qt Creator or build valgrind testapps "
"manually before executing this test.");
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);
if (on64bit())
QCOMPARE(frame.functionName(), QLatin1String("operator new(unsigned long)"));
else
QCOMPARE(frame.functionName(), QLatin1String("operator new(unsigned int)"));
}
{
const Frame frame = stack.frames().at(1);
QCOMPARE(frame.functionName(), QLatin1String("main"));
QCOMPARE(frame.line(), 5 + HEADER_LENGTH);
QCOMPARE(frame.object(), binary);
QCOMPARE(frame.fileName(), QLatin1String("main.cpp"));
QCOMPARE(QDir::cleanPath(frame.directory()), srcDirForApp("leak1"));
}
}
void ValgrindTestRunnerTest::testLeak2()
{
const QString binary = runTestBinary(QLatin1String("leak2/leak2"));
if (binary.isEmpty())
QSKIP("You need to pass BUILD_TESTS when building Qt Creator or build valgrind testapps "
"manually before executing this test.");
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(), QLatin1String("malloc"));
}
{
const Frame frame = stack.frames().at(1);
QCOMPARE(frame.functionName(), QLatin1String("strdup"));
}
{
const Frame frame = stack.frames().at(2);
if (on64bit()) {
QCOMPARE(frame.functionName(), QLatin1String("main"));
QCOMPARE(frame.line(), 7 + HEADER_LENGTH);
QCOMPARE(frame.object(), binary);
QCOMPARE(frame.fileName(), QLatin1String("main.cpp"));
QCOMPARE(QDir::cleanPath(frame.directory()), srcDirForApp("leak2"));
} else {
QCOMPARE(frame.functionName(), QLatin1String("(below main)"));
}
}
}
void ValgrindTestRunnerTest::testLeak3()
{
const QString binary = runTestBinary(QLatin1String("leak3/leak3"), QStringList() << "--show-reachable=yes");
if (binary.isEmpty())
QSKIP("You need to pass BUILD_TESTS when building Qt Creator or build valgrind testapps "
"manually before executing this test.");
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(), QLatin1String("malloc"));
}
{
const Frame frame = stack.frames().at(1);
QCOMPARE(frame.functionName(), QLatin1String("strdup"));
}
{
const Frame frame = stack.frames().at(2);
if (on64bit()) {
QCOMPARE(frame.functionName(), QLatin1String("main"));
QCOMPARE(frame.line(), 7 + HEADER_LENGTH);
QCOMPARE(frame.object(), binary);
QCOMPARE(frame.fileName(), QLatin1String("main.cpp"));
QCOMPARE(QDir::cleanPath(frame.directory()), srcDirForApp("leak3"));
} else {
QCOMPARE(frame.functionName(), QLatin1String("(below main)"));
}
}
}
void ValgrindTestRunnerTest::testLeak4()
{
const QString app("leak4");
const QString binary = runTestBinary(app + QLatin1Char('/') + app,
QStringList() << "--show-reachable=yes");
if (binary.isEmpty())
QSKIP("You need to pass BUILD_TESTS when building Qt Creator or build valgrind testapps "
"manually before executing this test.");
const QString srcDir = srcDirForApp("leak4");
QVERIFY(m_logMessages.isEmpty());
QCOMPARE(m_errors.count(), 3);
//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);
if (on64bit())
QCOMPARE(frame.functionName(), QLatin1String("operator new(unsigned long)"));
else
QCOMPARE(frame.functionName(), QLatin1String("operator new(unsigned int)"));
}
{
const Frame frame = stack.frames().at(1);
QCOMPARE(frame.functionName(), QLatin1String("Foo::Foo()"));
QCOMPARE(frame.line(), 6 + HEADER_LENGTH);
QCOMPARE(frame.object(), binary);
QCOMPARE(frame.fileName(), QLatin1String("main.cpp"));
QCOMPARE(QDir::cleanPath(frame.directory()), srcDir);
}
{
const Frame frame = stack.frames().at(2);
QCOMPARE(frame.functionName(), QLatin1String("main"));
QCOMPARE(frame.line(), 14 + HEADER_LENGTH);
QCOMPARE(frame.object(), binary);
QCOMPARE(frame.fileName(), QLatin1String("main.cpp"));
QCOMPARE(QDir::cleanPath(frame.directory()), srcDir);
}
}
//BEGIN second error
{
const Error error = m_errors.at(1);
QCOMPARE(error.kind(), int(Leak_DefinitelyLost));
QCOMPARE(error.leakedBlocks(), qint64(1));
if (on64bit())
QCOMPARE(error.leakedBytes(), quint64(16));
else
QCOMPARE(error.leakedBytes(), quint64(12));
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);
if (on64bit())
QCOMPARE(frame.functionName(), QLatin1String("operator new(unsigned long)"));
else
QCOMPARE(frame.functionName(), QLatin1String("operator new(unsigned int)"));
}
{
const Frame frame = stack.frames().at(1);
QCOMPARE(frame.functionName(), QLatin1String("main"));
QCOMPARE(frame.line(), 14 + HEADER_LENGTH);
QCOMPARE(frame.object(), binary);
QCOMPARE(frame.fileName(), QLatin1String("main.cpp"));
QCOMPARE(QDir::cleanPath(frame.directory()), srcDir);
}
}
// TODO add third error check
}
void ValgrindTestRunnerTest::testUninit1()
{
const QString app("uninit1");
const QString binary = runTestBinary(app + QLatin1Char('/') + app);
if (binary.isEmpty())
QSKIP("You need to pass BUILD_TESTS when building Qt Creator or build valgrind testapps "
"manually before executing this test.");
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(), QLatin1String("main"));
QCOMPARE(frame.line(), 4 + HEADER_LENGTH);
QCOMPARE(frame.object(), binary);
QCOMPARE(frame.fileName(), 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(), QLatin1String("main"));
QCOMPARE(frame.line(), 2 + HEADER_LENGTH);
QCOMPARE(frame.object(), binary);
QCOMPARE(frame.fileName(), QLatin1String("main.cpp"));
QCOMPARE(QDir::cleanPath(frame.directory()), srcDir);
}
}
void ValgrindTestRunnerTest::testUninit2()
{
const QString app("uninit2");
m_expectCrash = true;
const QString binary = runTestBinary(app + QLatin1Char('/') + app);
if (binary.isEmpty())
QSKIP("You need to pass BUILD_TESTS when building Qt Creator or build valgrind testapps "
"manually before executing this test.");
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(), QLatin1String("main"));
QCOMPARE(frame.line(), 4 + HEADER_LENGTH);
QCOMPARE(frame.object(), binary);
QCOMPARE(frame.fileName(), 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(), QLatin1String("main"));
QCOMPARE(frame.line(), 2 + HEADER_LENGTH);
QCOMPARE(frame.object(), binary);
QCOMPARE(frame.fileName(), 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(), QLatin1String("main"));
QCOMPARE(frame.line(), 4 + HEADER_LENGTH);
QCOMPARE(frame.object(), binary);
QCOMPARE(frame.fileName(), QLatin1String("main.cpp"));
QCOMPARE(QDir::cleanPath(frame.directory()), srcDir);
}
}
void ValgrindTestRunnerTest::testUninit3()
{
const QString app("uninit3");
m_expectCrash = true;
const QString binary = runTestBinary(app + QLatin1Char('/') + app);
if (binary.isEmpty())
QSKIP("You need to pass BUILD_TESTS when building Qt Creator or build valgrind testapps "
"manually before executing this test.");
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(), QLatin1String("main"));
QCOMPARE(frame.line(), 4 + HEADER_LENGTH);
QCOMPARE(frame.object(), binary);
QCOMPARE(frame.fileName(), 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(), QLatin1String("main"));
QCOMPARE(frame.line(), 2 + HEADER_LENGTH);
QCOMPARE(frame.object(), binary);
QCOMPARE(frame.fileName(), 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(), QLatin1String("main"));
QCOMPARE(frame.line(), 4 + HEADER_LENGTH);
QCOMPARE(frame.object(), binary);
QCOMPARE(frame.fileName(), QLatin1String("main.cpp"));
QCOMPARE(QDir::cleanPath(frame.directory()), srcDir);
}
}
void ValgrindTestRunnerTest::testSyscall()
{
const QString app("syscall");
const QString binary = runTestBinary(app + QLatin1Char('/') + app);
if (binary.isEmpty())
QSKIP("You need to pass BUILD_TESTS when building Qt Creator or build valgrind testapps "
"manually before executing this test.");
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));
if (on64bit()) {
QCOMPARE(stack.frames().count(), 4);
{
const Frame frame = stack.frames().at(0);
QCOMPARE(frame.functionName(), QLatin1String("_Exit"));
}
{
const Frame frame = stack.frames().at(1);
QCOMPARE(frame.functionName(), QLatin1String("__run_exit_handlers"));
}
{
const Frame frame = stack.frames().at(2);
QCOMPARE(frame.functionName(), QLatin1String("exit"));
}
{
const Frame frame = stack.frames().at(3);
QCOMPARE(frame.functionName(), QLatin1String("(below main)"));
}
} else {
QCOMPARE(stack.frames().count(), 1);
{
const Frame frame = stack.frames().at(0);
QCOMPARE(frame.functionName(), QLatin1String("_Exit"));
}
}
}
//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(), QLatin1String("main"));
QCOMPARE(frame.line(), 2 + HEADER_LENGTH);
QCOMPARE(frame.object(), binary);
QCOMPARE(frame.fileName(), QLatin1String("main.cpp"));
QCOMPARE(QDir::cleanPath(frame.directory()), srcDir);
}
}
void ValgrindTestRunnerTest::testFree1()
{
const QString app("free1");
const QString binary = runTestBinary(app + QLatin1Char('/') + app);
if (binary.isEmpty())
QSKIP("You need to pass BUILD_TESTS when building Qt Creator or build valgrind testapps "
"manually before executing this test.");
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(), QLatin1String("operator delete(void*)"));
}
{
const Frame frame = stack.frames().last();
QCOMPARE(frame.functionName(), QLatin1String("main"));
QCOMPARE(frame.line(), 7 + HEADER_LENGTH);
QCOMPARE(frame.object(), binary);
QCOMPARE(frame.fileName(), 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(), QLatin1String("operator delete(void*)"));
}
{
const Frame frame = stack.frames().last();
QCOMPARE(frame.functionName(), QLatin1String("main"));
QCOMPARE(frame.line(), 6 + HEADER_LENGTH);
QCOMPARE(frame.object(), binary);
QCOMPARE(frame.fileName(), QLatin1String("main.cpp"));
QCOMPARE(QDir::cleanPath(frame.directory()), srcDir);
}
}
}
void ValgrindTestRunnerTest::testFree2()
{
const QString app("free2");
const QString binary = runTestBinary(app + QLatin1Char('/') + app);
if (binary.isEmpty())
QSKIP("You need to pass BUILD_TESTS when building Qt Creator or build valgrind testapps "
"manually before executing this test.");
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(), QLatin1String("free"));
}
{
const Frame frame = stack.frames().last();
QCOMPARE(frame.functionName(), QLatin1String("main"));
QCOMPARE(frame.line(), 6 + HEADER_LENGTH);
QCOMPARE(frame.object(), binary);
QCOMPARE(frame.fileName(), 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();
if (on64bit())
QCOMPARE(frame.functionName(), QLatin1String("operator new(unsigned long)"));
else
QCOMPARE(frame.functionName(), QLatin1String("operator new(unsigned int)"));
}
{
const Frame frame = stack.frames().last();
QCOMPARE(frame.functionName(), QLatin1String("main"));
QCOMPARE(frame.line(), 5 + HEADER_LENGTH);
QCOMPARE(frame.object(), binary);
QCOMPARE(frame.fileName(), QLatin1String("main.cpp"));
QCOMPARE(QDir::cleanPath(frame.directory()), srcDir);
}
}
}
void ValgrindTestRunnerTest::testInvalidjump()
{
const QString app("invalidjump");
m_expectCrash = true;
const QString binary = runTestBinary(app + QLatin1Char('/') + app);
if (binary.isEmpty())
QSKIP("You need to pass BUILD_TESTS when building Qt Creator or build valgrind testapps "
"manually before executing this test.");
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(), QLatin1String("(below main)"));
}
}
void ValgrindTestRunnerTest::testOverlap()
{
const QString app("overlap");
m_expectCrash = true;
const QString binary = runTestBinary(app + QLatin1Char('/') + app);
if (binary.isEmpty())
QSKIP("You need to pass BUILD_TESTS when building Qt Creator or build valgrind testapps "
"manually before executing this test.");
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);
QVERIFY(frame.functionName().startsWith(QLatin1String("memcpy")));
}
{
const Frame frame = stack.frames().last();
QCOMPARE(frame.functionName(), QLatin1String("main"));
QCOMPARE(frame.line(), 6 + HEADER_LENGTH);
QCOMPARE(frame.object(), binary);
QCOMPARE(frame.fileName(), QLatin1String("main.cpp"));
QCOMPARE(QDir::cleanPath(frame.directory()), srcDir);
}
}
} // namespace Test
} // namespace Valgrind

View File

@@ -0,0 +1,88 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Author: Milian Wolff, KDAB (milian.wolff@kdab.com)
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <QObject>
#include <QStringList>
#include "xmlprotocol/error.h"
namespace Valgrind {
namespace XmlProtocol {
class ThreadedParser;
}
namespace Memcheck {
class MemcheckRunner;
}
namespace Test {
class ValgrindTestRunnerTest : public QObject
{
Q_OBJECT
public:
explicit ValgrindTestRunnerTest(QObject *parent = 0);
private slots:
void init();
void cleanup();
void testLeak1();
void testLeak2();
void testLeak3();
void testLeak4();
void testUninit1();
void testUninit2();
void testUninit3();
void testFree1();
void testFree2();
void testInvalidjump();
void testSyscall();
void testOverlap();
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 = 0;
Memcheck::MemcheckRunner *m_runner = 0;
QList<QByteArray> m_logMessages;
QList<XmlProtocol::Error> m_errors;
bool m_expectCrash = false;
};
} // namespace Test
} // namespace Valgrind