From bbd60cacda707c17c6f3b9c4e4b390ad85743a92 Mon Sep 17 00:00:00 2001 From: Mike McQuaid <mike@mikemcquaid.com> Date: Fri, 4 Mar 2011 12:15:18 +0100 Subject: [PATCH] Add valgrindfake emulation/testing tool. Merge-request: 260 Reviewed-by: hjk <qtc-committer@nokia.com> --- .gitignore | 1 + src/tools/tools.pro | 4 + src/tools/valgrindfake/main.cpp | 158 ++++++++++++++++++++ src/tools/valgrindfake/outputgenerator.cpp | 159 +++++++++++++++++++++ src/tools/valgrindfake/outputgenerator.h | 84 +++++++++++ src/tools/valgrindfake/valgrindfake.pro | 10 ++ 6 files changed, 416 insertions(+) create mode 100644 src/tools/valgrindfake/main.cpp create mode 100644 src/tools/valgrindfake/outputgenerator.cpp create mode 100644 src/tools/valgrindfake/outputgenerator.h create mode 100644 src/tools/valgrindfake/valgrindfake.pro diff --git a/.gitignore b/.gitignore index f5d119ec6e4..84a479d1f72 100644 --- a/.gitignore +++ b/.gitignore @@ -87,6 +87,7 @@ share/doc/qtcreator/qtcreator.qch src/tools/gen-cpp-ast/generate-ast src/tools/mkvisitor/cplusplus0 src/tools/qml/qmldump/qmldump +src/tools/valgrindfake/valgrind-fake # Tests #------ diff --git a/src/tools/tools.pro b/src/tools/tools.pro index 204f0b69300..e63bca5304d 100644 --- a/src/tools/tools.pro +++ b/src/tools/tools.pro @@ -3,6 +3,10 @@ TEMPLATE = subdirs win32:SUBDIRS = qtcdebugger SUBDIRS += qtpromaker +!win32 { + SUBDIRS += valgrindfake +} + QT_BREAKPAD_ROOT_PATH = $$(QT_BREAKPAD_ROOT_PATH) !isEmpty(QT_BREAKPAD_ROOT_PATH) { SUBDIRS += qtcrashhandler diff --git a/src/tools/valgrindfake/main.cpp b/src/tools/valgrindfake/main.cpp new file mode 100644 index 00000000000..9e79b9043a8 --- /dev/null +++ b/src/tools/valgrindfake/main.cpp @@ -0,0 +1,158 @@ +/************************************************************************** +** +** 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 <QCoreApplication> +#include <QStringList> +#include <QTextStream> +#include <QDir> +#include <QTcpSocket> +#include <QXmlStreamReader> +#include <QProcessEnvironment> + +#include "outputgenerator.h" + +using namespace Valgrind::Fake; + +QTextStream qerr(stderr); +QTextStream qout(stdout); + +void usage(QTextStream& stream) +{ + stream << "valgrind-fake OPTIONS" << endl; + stream << endl; + stream << " REQUIRED OPTIONS:" << endl; + stream << " --xml-socket=ipaddr:port \tXML output to socket ipaddr:port" << endl; + stream << " -i, --xml-input FILE \tpath to a XML file as generated by valgrind" << endl; + stream << endl; + stream << " OPTIONAL OPTIONS:" << endl; + stream << " -c, --crash \tcrash randomly" << endl; + stream << " -g, --garbage \toutput invalid XML somewhere" << endl; + stream << " -w, --wait SECONDS \twait randomly for the given amount of seconds" << endl; + stream << " -h, --help \tprint help" << endl; +} + +int main(int argc, char** argv) +{ + QCoreApplication app(argc, argv); + + const QStringList args = app.arguments(); + QString arg_port; + QString arg_server; + QString arg_xmlFile; + bool arg_crash = false; + bool arg_garbage = false; + uint arg_wait = 0; + + const QProcessEnvironment sysEnv = QProcessEnvironment::systemEnvironment(); + arg_xmlFile = sysEnv.value("QCIT_INPUT_FILE"); + + for (int i = 1; i < args.size(); ++i) { + const QString& arg = args.at(i); + if (arg.startsWith(QLatin1String("--xml-socket="))) { + arg_server = arg.mid(13, arg.indexOf(':') - 13); + arg_port = arg.mid(13 + arg_server.length() + 1); + } else if (args.size() > i + 1 + && (args.at(i) == QLatin1String("-i") + || args.at(i) == QLatin1String("--xml-input"))) { + arg_xmlFile = args.at(i+1); + ++i; + } else if (arg == QLatin1String("-c") || arg == QLatin1String("--crash")) { + arg_crash = true; + } else if (arg == QLatin1String("-g") || arg == QLatin1String("--garbage")) { + arg_garbage = true; + } else if (args.size() > i + 1 && (arg == QLatin1String("-w") || arg == QLatin1String("--wait"))) { + bool ok; + arg_wait = args.at(i+1).toUInt(&ok); + if (!ok) { + qerr << "ERROR: invalid wait time given" << args.at(i+1) << endl; + usage(qerr); + return 4; + } + } else if (args.at(i) == QLatin1String("--help") || args.at(i) == QLatin1String("-h")) { + usage(qout); + return 0; + } + } + + if (arg_xmlFile.isEmpty()) { + qerr << "ERROR: no XML input file given" << endl; + usage(qerr); + return 1; + } + if (arg_server.isEmpty()) { + qerr << "ERROR: no server given" << endl; + usage(qerr); + return 2; + } + if (arg_port.isEmpty()) { + qerr << "ERROR: no port given" << endl; + usage(qerr); + return 3; + } + + QFile xmlFile(arg_xmlFile); + if (!xmlFile.exists() || !xmlFile.open(QIODevice::ReadOnly)) { + qerr << "ERROR: invalid XML file" << endl; + usage(qerr); + return 10; + } + bool ok = false; + quint16 port = arg_port.toUInt(&ok); + if (!ok) { + qerr << "ERROR: invalid port" << endl; + usage(qerr); + return 30; + } + + QTcpSocket socket; + socket.connectToHost(arg_server, port, QIODevice::WriteOnly); + if (!socket.isOpen()) { + qerr << "ERROR: could not open socket to server:" << arg_server << ":" << port << endl; + usage(qerr); + return 20; + } + if (!socket.waitForConnected()) { + qerr << "ERROR: could not connect to socket: " << socket.errorString() << endl; + return 21; + } + + OutputGenerator generator(&socket, &xmlFile); + QObject::connect(&generator, SIGNAL(finished()), &app, SLOT(quit())); + generator.setCrashRandomly(arg_crash); + generator.setOutputGarbage(arg_garbage); + generator.setWait(arg_wait); + + return app.exec(); +} diff --git a/src/tools/valgrindfake/outputgenerator.cpp b/src/tools/valgrindfake/outputgenerator.cpp new file mode 100644 index 00000000000..2a6225a8bb8 --- /dev/null +++ b/src/tools/valgrindfake/outputgenerator.cpp @@ -0,0 +1,159 @@ +/************************************************************************** +** +** 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 "outputgenerator.h" + +#include <QAbstractSocket> +#include <QIODevice> +#include <QTextStream> +#include <QCoreApplication> +#include <QStringList> +#include <QDebug> + +using namespace Valgrind::Fake; + +OutputGenerator::OutputGenerator(QAbstractSocket *output, QIODevice *input) : + m_output(output), + m_input(input), + m_finished(false), + m_crash(false), + m_garbage(false), + m_wait(0) +{ + Q_ASSERT(input->isOpen()); + Q_ASSERT(input->isReadable()); + + m_timer.setSingleShot(true); + m_timer.start(); + + connect(&m_timer, SIGNAL(timeout()), + this, SLOT(writeOutput())); +} + +void OutputGenerator::setCrashRandomly(bool enable) +{ + m_crash = enable; +} + +void OutputGenerator::setOutputGarbage(bool enable) +{ + m_garbage = enable; +} + +void OutputGenerator::setWait(uint seconds) +{ + m_wait = seconds; +} + +#include <iostream> + +static bool blockingWrite(QIODevice *dev, const QByteArray &ba) +{ + const qint64 toWrite = ba.size(); + qint64 written = 0; + while (written < ba.size()) { + const qint64 n = dev->write(ba.constData() + written, toWrite - written); + if (n < 0) + return false; + written += n; + } + + return true; +} + +void OutputGenerator::produceRuntimeError() +{ + if (m_crash) { + std::cerr << "Goodbye, cruel world" << std::endl; + int zero = 0; // hide the error at compile-time to avoid a compiler warning + int i = 1 / zero; + Q_UNUSED(i); + Q_ASSERT(false); + } + else if (m_garbage) { + std::cerr << "Writing garbage" << std::endl; + blockingWrite(m_output, "<</GARBAGE = '\"''asdfaqre"); + m_output->flush(); + } else if (m_wait) { + qDebug() << "waiting in fake valgrind for " << m_wait << " seconds..." << endl; + sleep(m_wait); + } +} + + +void OutputGenerator::writeOutput() +{ + m_timer.setInterval(qrand() % 1000); + + int lines = 0; + while (!m_input->atEnd()) { + qint64 lastPos = m_input->pos(); + QByteArray line = m_input->readLine(); + if (lines > 0 && !m_finished && line.contains("<error>")) { + if ((m_crash || m_garbage || m_wait) && qrand() % 10 == 1) { + produceRuntimeError(); + m_timer.start(); + return; + } + + m_input->seek(lastPos); + m_timer.start(); + return; + } else { + if (!m_finished && line.contains("<state>FINISHED</state>")) { + m_finished = true; + if (m_crash || m_garbage || m_wait) { + produceRuntimeError(); + m_timer.start(); + return; + } + } + + if (!blockingWrite(m_output, line)) { + std::cerr << "Writing to socket failed: " << qPrintable(m_output->errorString()) << std::endl; + emit finished(); + return; + } + m_output->flush(); + ++lines; + } + } + + Q_ASSERT(m_input->atEnd()); + + while (m_output->bytesToWrite() > 0) + m_output->waitForBytesWritten(-1); + emit finished(); +} diff --git a/src/tools/valgrindfake/outputgenerator.h b/src/tools/valgrindfake/outputgenerator.h new file mode 100644 index 00000000000..d9e991d398e --- /dev/null +++ b/src/tools/valgrindfake/outputgenerator.h @@ -0,0 +1,84 @@ +/************************************************************************** +** +** 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 +** +** 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. +** +** 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 LIBVALGRIND_FAKE_OUTPUTGENERATOR_H +#define LIBVALGRIND_FAKE_OUTPUTGENERATOR_H + +#include <QObject> +#include <QTimer> +#include <QTextStream> + + +QT_BEGIN_NAMESPACE +class QAbstractSocket; +class QIODevice; +QT_END_NAMESPACE + +namespace Valgrind { +namespace Fake { + +class OutputGenerator : public QObject +{ + Q_OBJECT + +public: + explicit OutputGenerator(QAbstractSocket *output, QIODevice *input); + + void setCrashRandomly(bool enable); + void setOutputGarbage(bool enable); + void setWait(uint seconds); + +Q_SIGNALS: + void finished(); +private slots: + /// write output to the stream until the next error + void writeOutput(); + +private: + void produceRuntimeError(); + + QAbstractSocket *m_output; + QIODevice *m_input; + QTimer m_timer; + bool m_finished; + bool m_crash; + bool m_garbage; + uint m_wait; +}; + +} // namespace Fake +} // namespace Valgrind + +#endif // LIBVALGRIND_FAKE_OUTPUTGENERATOR_H diff --git a/src/tools/valgrindfake/valgrindfake.pro b/src/tools/valgrindfake/valgrindfake.pro new file mode 100644 index 00000000000..1b26d7b93aa --- /dev/null +++ b/src/tools/valgrindfake/valgrindfake.pro @@ -0,0 +1,10 @@ +TEMPLATE = app +TARGET = valgrind-fake + +QT += network xml + +macx:CONFIG -= app_bundle + +HEADERS += outputgenerator.h +SOURCES += main.cpp \ + outputgenerator.cpp -- GitLab