1 /**************************************************************************
3 ** This file is part of Qt Creator
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
7 ** Author: Milian Wolff, KDAB (milian.wolff@kdab.com)
9 ** Contact: Nokia Corporation (info@qt.nokia.com)
12 ** GNU Lesser General Public License Usage
14 ** This file may be used under the terms of the GNU Lesser General Public
15 ** License version 2.1 as published by the Free Software Foundation and
16 ** appearing in the file LICENSE.LGPL included in the packaging of this file.
17 ** Please review the following information to ensure the GNU Lesser General
18 ** Public License version 2.1 requirements will be met:
19 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
21 ** In addition, as a special exception, Nokia gives you certain additional
22 ** rights. These rights are described in the Nokia Qt LGPL Exception
23 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27 ** Alternatively, this file may be used in accordance with the terms and
28 ** conditions contained in a signed written agreement between you and Nokia.
30 ** If you have questions regarding the use of this file, please contact
31 ** Nokia at qt-info@nokia.com.
33 **************************************************************************/
35 #include "testrunner.h"
37 #include <valgrind/xmlprotocol/frame.h>
38 #include <valgrind/xmlprotocol/stack.h>
39 #include <valgrind/xmlprotocol/suppression.h>
40 #include <valgrind/xmlprotocol/threadedparser.h>
41 #include <valgrind/xmlprotocol/parser.h>
42 #include <valgrind/memcheck/memcheckrunner.h>
49 const QString appSrcDir(TESTRUNNER_SRC_DIR);
50 const QString appBinDir(TESTRUNNER_APP_DIR);
52 QString srcDirForApp(const QString &app)
54 return appSrcDir + QDir::separator() + app;
57 QTEST_MAIN(Valgrind::TestRunner)
59 using namespace Valgrind;
60 using namespace Valgrind::XmlProtocol;
61 using namespace Valgrind::Memcheck;
63 //BEGIN Test Helpers and boilterplate code
65 TestRunner::TestRunner(QObject *parent)
70 qRegisterMetaType<Error>();
73 QString TestRunner::runTestBinary(const QString &binary, const QStringList &vArgs)
75 const QString binPath = appBinDir + QDir::separator() + binary;
76 Q_ASSERT(QFileInfo(binPath).isExecutable());
77 m_runner->setValgrindArguments(QStringList() << "--num-callers=50" << "--track-origins=yes" << vArgs);
78 m_runner->setDebuggeeExecutable(binPath);
80 m_runner->waitForFinished();
84 void TestRunner::logMessageReceived(const QByteArray &message)
86 qDebug() << "log message received:" << message;
87 m_logMessages << message;
90 void TestRunner::internalError(const QString &error)
93 QFAIL(qPrintable(error));
95 qDebug() << "expected crash:" << error;
98 void TestRunner::error(const Error &error)
103 void TestRunner::cleanup()
112 m_logMessages.clear();
114 m_expectCrash = false;
117 void TestRunner::init()
119 Q_ASSERT(m_logMessages.isEmpty());
122 m_runner = new MemcheckRunner;
123 m_runner->setValgrindExecutable(QLatin1String("valgrind"));
124 m_runner->setProcessChannelMode(QProcess::ForwardedChannels);
125 connect(m_runner, SIGNAL(logMessageReceived(QByteArray)),
126 this, SLOT(logMessageReceived(QByteArray)));
127 connect(m_runner, SIGNAL(processErrorReceived(QString, QProcess::ProcessError)),
128 this, SLOT(internalError(QString)));
130 m_parser = new ThreadedParser;
131 connect(m_parser, SIGNAL(internalError(QString)),
132 this, SLOT(internalError(QString)));
133 connect(m_parser, SIGNAL(error(Valgrind::XmlProtocol::Error)),
134 this, SLOT(error(Valgrind::XmlProtocol::Error)));
136 m_runner->setParser(m_parser);
139 //BEGIN: Actual test cases
141 void TestRunner::testLeak1()
143 const QString binary = runTestBinary(QLatin1String("leak1/leak1"));
145 QVERIFY(m_logMessages.isEmpty());
147 QCOMPARE(m_errors.count(), 1);
148 const Error error = m_errors.first();
149 QCOMPARE(error.kind(), int(Leak_DefinitelyLost));
150 QCOMPARE(error.leakedBlocks(), qint64(1));
151 QCOMPARE(error.leakedBytes(), quint64(8));
152 QCOMPARE(error.stacks().count(), 1);
153 const Stack stack = error.stacks().first();
154 QCOMPARE(stack.line(), qint64(-1));
155 QCOMPARE(stack.frames().count(), 2);
157 const Frame frame = stack.frames().at(0);
158 QCOMPARE(frame.functionName(), QString("operator new(unsigned long)"));
161 const Frame frame = stack.frames().at(1);
162 QCOMPARE(frame.functionName(), QString("main"));
163 QCOMPARE(frame.line(), 5);
165 QCOMPARE(frame.object(), binary);
166 QCOMPARE(frame.file(), QLatin1String("main.cpp"));
167 QCOMPARE(QDir::cleanPath(frame.directory()), srcDirForApp("leak1"));
171 void TestRunner::testLeak2()
173 const QString binary = runTestBinary(QLatin1String("leak2/leak2"));
175 QVERIFY(m_logMessages.isEmpty());
177 QCOMPARE(m_errors.count(), 1);
178 const Error error = m_errors.first();
179 QCOMPARE(error.kind(), int(Leak_PossiblyLost));
180 QCOMPARE(error.leakedBlocks(), qint64(1));
181 QCOMPARE(error.leakedBytes(), quint64(5));
182 QCOMPARE(error.stacks().count(), 1);
183 const Stack stack = error.stacks().first();
184 QCOMPARE(stack.line(), qint64(-1));
185 QCOMPARE(stack.frames().count(), 3);
187 const Frame frame = stack.frames().at(0);
188 QCOMPARE(frame.functionName(), QString("malloc"));
191 const Frame frame = stack.frames().at(1);
192 QCOMPARE(frame.functionName(), QString("strdup"));
195 const Frame frame = stack.frames().at(2);
196 QCOMPARE(frame.functionName(), QString("main"));
197 QCOMPARE(frame.line(), 7);
199 QCOMPARE(frame.object(), binary);
200 QCOMPARE(frame.file(), QLatin1String("main.cpp"));
201 QCOMPARE(QDir::cleanPath(frame.directory()), srcDirForApp("leak2"));
205 void TestRunner::testLeak3()
207 const QString binary = runTestBinary(QLatin1String("leak3/leak3"), QStringList() << "--show-reachable=yes");
209 QVERIFY(m_logMessages.isEmpty());
211 QCOMPARE(m_errors.count(), 1);
212 const Error error = m_errors.first();
213 QCOMPARE(error.kind(), int(Leak_StillReachable));
214 QCOMPARE(error.leakedBlocks(), qint64(1));
215 QCOMPARE(error.leakedBytes(), quint64(5));
216 QCOMPARE(error.stacks().count(), 1);
217 const Stack stack = error.stacks().first();
218 QCOMPARE(stack.line(), qint64(-1));
219 QCOMPARE(stack.frames().count(), 3);
221 const Frame frame = stack.frames().at(0);
222 QCOMPARE(frame.functionName(), QString("malloc"));
225 const Frame frame = stack.frames().at(1);
226 QCOMPARE(frame.functionName(), QString("strdup"));
229 const Frame frame = stack.frames().at(2);
230 QCOMPARE(frame.functionName(), QString("main"));
231 QCOMPARE(frame.line(), 7);
233 QCOMPARE(frame.object(), binary);
234 QCOMPARE(frame.file(), QLatin1String("main.cpp"));
235 QCOMPARE(QDir::cleanPath(frame.directory()), srcDirForApp("leak3"));
239 void TestRunner::testLeak4()
241 const QString app("leak4");
242 const QString binary = runTestBinary(app + QDir::separator() + app,
243 QStringList() << "--show-reachable=yes");
244 const QString srcDir = srcDirForApp("leak4");
246 QVERIFY(m_logMessages.isEmpty());
248 QCOMPARE(m_errors.count(), 2);
251 const Error error = m_errors.first();
252 QCOMPARE(error.kind(), int(Leak_IndirectlyLost));
253 QCOMPARE(error.leakedBlocks(), qint64(1));
254 QCOMPARE(error.leakedBytes(), quint64(8));
255 QCOMPARE(error.stacks().count(), 1);
256 const Stack stack = error.stacks().first();
257 QCOMPARE(stack.line(), qint64(-1));
258 QCOMPARE(stack.frames().count(), 3);
260 const Frame frame = stack.frames().at(0);
261 QCOMPARE(frame.functionName(), QString("operator new(unsigned long)"));
264 const Frame frame = stack.frames().at(2);
265 QCOMPARE(frame.functionName(), QString("main"));
266 QCOMPARE(frame.line(), 13);
268 QCOMPARE(frame.object(), binary);
269 QCOMPARE(frame.file(), QLatin1String("main.cpp"));
270 QCOMPARE(QDir::cleanPath(frame.directory()), srcDir);
273 const Frame frame = stack.frames().at(1);
274 QCOMPARE(frame.functionName(), QString("foo::foo()"));
275 QCOMPARE(frame.line(), 5);
277 QCOMPARE(frame.object(), binary);
278 QCOMPARE(frame.file(), QLatin1String("main.cpp"));
279 QCOMPARE(QDir::cleanPath(frame.directory()), srcDir);
282 const Frame frame = stack.frames().at(2);
283 QCOMPARE(frame.functionName(), QString("main"));
284 QCOMPARE(frame.line(), 13);
286 QCOMPARE(frame.object(), binary);
287 QCOMPARE(frame.file(), QLatin1String("main.cpp"));
288 QCOMPARE(QDir::cleanPath(frame.directory()), srcDir);
293 const Error error = m_errors.last();
294 QCOMPARE(error.kind(), int(Leak_DefinitelyLost));
295 QCOMPARE(error.leakedBlocks(), qint64(1));
296 QCOMPARE(error.leakedBytes(), quint64(16));
297 QCOMPARE(error.stacks().count(), 1);
298 const Stack stack = error.stacks().first();
299 QCOMPARE(stack.line(), qint64(-1));
300 QCOMPARE(stack.frames().count(), 2);
302 const Frame frame = stack.frames().at(0);
303 QCOMPARE(frame.functionName(), QString("operator new(unsigned long)"));
306 const Frame frame = stack.frames().at(1);
307 QCOMPARE(frame.functionName(), QString("main"));
308 QCOMPARE(frame.line(), 13);
310 QCOMPARE(frame.object(), binary);
311 QCOMPARE(frame.file(), QLatin1String("main.cpp"));
312 QCOMPARE(QDir::cleanPath(frame.directory()), srcDir);
317 void TestRunner::uninit1()
319 const QString app("uninit1");
320 const QString binary = runTestBinary(app + QDir::separator() + app);
321 const QString srcDir = srcDirForApp(app);
323 QVERIFY(m_logMessages.isEmpty());
325 QCOMPARE(m_errors.count(), 1);
326 const Error error = m_errors.first();
327 QCOMPARE(error.kind(), int(UninitCondition));
328 QCOMPARE(error.stacks().count(), 2);
331 const Stack stack = error.stacks().first();
332 QCOMPARE(stack.line(), qint64(-1));
333 QCOMPARE(stack.frames().count(), 1);
335 const Frame frame = stack.frames().first();
336 QCOMPARE(frame.functionName(), QString("main"));
337 QCOMPARE(frame.line(), 4);
339 QCOMPARE(frame.object(), binary);
340 QCOMPARE(frame.file(), QLatin1String("main.cpp"));
341 QCOMPARE(QDir::cleanPath(frame.directory()), srcDir);
345 const Stack stack = error.stacks().last();
346 QCOMPARE(stack.line(), qint64(-1));
347 QCOMPARE(stack.frames().count(), 1);
349 const Frame frame = stack.frames().first();
350 QCOMPARE(frame.functionName(), QString("main"));
351 QCOMPARE(frame.line(), 2);
353 QCOMPARE(frame.object(), binary);
354 QCOMPARE(frame.file(), QLatin1String("main.cpp"));
355 QCOMPARE(QDir::cleanPath(frame.directory()), srcDir);
359 void TestRunner::uninit2()
361 const QString app("uninit2");
362 m_expectCrash = true;
363 const QString binary = runTestBinary(app + QDir::separator() + app);
364 const QString srcDir = srcDirForApp(app);
366 QVERIFY(m_logMessages.isEmpty());
368 QCOMPARE(m_errors.count(), 2);
371 const Error error = m_errors.first();
372 QCOMPARE(error.kind(), int(UninitValue));
373 QCOMPARE(error.stacks().count(), 2);
376 const Stack stack = error.stacks().first();
377 QCOMPARE(stack.line(), qint64(-1));
378 QCOMPARE(stack.frames().count(), 1);
380 const Frame frame = stack.frames().first();
381 QCOMPARE(frame.functionName(), QString("main"));
382 QCOMPARE(frame.line(), 4);
384 QCOMPARE(frame.object(), binary);
385 QCOMPARE(frame.file(), QLatin1String("main.cpp"));
386 QCOMPARE(QDir::cleanPath(frame.directory()), srcDir);
390 const Stack stack = error.stacks().last();
391 QCOMPARE(stack.line(), qint64(-1));
392 QCOMPARE(stack.frames().count(), 1);
394 const Frame frame = stack.frames().first();
395 QCOMPARE(frame.functionName(), QString("main"));
396 QCOMPARE(frame.line(), 2);
398 QCOMPARE(frame.object(), binary);
399 QCOMPARE(frame.file(), QLatin1String("main.cpp"));
400 QCOMPARE(QDir::cleanPath(frame.directory()), srcDir);
405 const Error error = m_errors.last();
406 QCOMPARE(error.kind(), int(InvalidWrite));
407 QCOMPARE(error.stacks().count(), 1);
409 const Stack stack = error.stacks().first();
410 QCOMPARE(stack.line(), qint64(-1));
411 QCOMPARE(stack.frames().count(), 1);
413 const Frame frame = stack.frames().first();
414 QCOMPARE(frame.functionName(), QString("main"));
415 QCOMPARE(frame.line(), 4);
417 QCOMPARE(frame.object(), binary);
418 QCOMPARE(frame.file(), QLatin1String("main.cpp"));
419 QCOMPARE(QDir::cleanPath(frame.directory()), srcDir);
423 void TestRunner::uninit3()
425 const QString app("uninit3");
426 m_expectCrash = true;
427 const QString binary = runTestBinary(app + QDir::separator() + app);
428 const QString srcDir = srcDirForApp(app);
430 QVERIFY(m_logMessages.isEmpty());
432 QCOMPARE(m_errors.count(), 2);
435 const Error error = m_errors.first();
436 QCOMPARE(error.kind(), int(UninitValue));
437 QCOMPARE(error.stacks().count(), 2);
440 const Stack stack = error.stacks().first();
441 QCOMPARE(stack.line(), qint64(-1));
442 QCOMPARE(stack.frames().count(), 1);
444 const Frame frame = stack.frames().first();
445 QCOMPARE(frame.functionName(), QString("main"));
446 QCOMPARE(frame.line(), 3);
448 QCOMPARE(frame.object(), binary);
449 QCOMPARE(frame.file(), QLatin1String("main.cpp"));
450 QCOMPARE(QDir::cleanPath(frame.directory()), srcDir);
454 const Stack stack = error.stacks().last();
455 QCOMPARE(stack.line(), qint64(-1));
456 QCOMPARE(stack.frames().count(), 1);
458 const Frame frame = stack.frames().first();
459 QCOMPARE(frame.functionName(), QString("main"));
460 QCOMPARE(frame.line(), 1);
462 QCOMPARE(frame.object(), binary);
463 QCOMPARE(frame.file(), QLatin1String("main.cpp"));
464 QCOMPARE(QDir::cleanPath(frame.directory()), srcDir);
469 const Error error = m_errors.last();
470 QCOMPARE(error.kind(), int(InvalidRead));
471 QCOMPARE(error.stacks().count(), 1);
473 const Stack stack = error.stacks().first();
474 QCOMPARE(stack.line(), qint64(-1));
475 QCOMPARE(stack.frames().count(), 1);
477 const Frame frame = stack.frames().first();
478 QCOMPARE(frame.functionName(), QString("main"));
479 QCOMPARE(frame.line(), 3);
481 QCOMPARE(frame.object(), binary);
482 QCOMPARE(frame.file(), QLatin1String("main.cpp"));
483 QCOMPARE(QDir::cleanPath(frame.directory()), srcDir);
487 void TestRunner::syscall()
489 const QString app("syscall");
490 const QString binary = runTestBinary(app + QDir::separator() + app);
491 const QString srcDir = srcDirForApp(app);
493 QVERIFY(m_logMessages.isEmpty());
495 QCOMPARE(m_errors.count(), 1);
496 const Error error = m_errors.first();
497 QCOMPARE(error.kind(), int(SyscallParam));
498 QCOMPARE(error.stacks().count(), 2);
501 const Stack stack = error.stacks().first();
502 QCOMPARE(stack.line(), qint64(-1));
503 QCOMPARE(stack.frames().count(), 3);
506 ///TODO: is this platform specific?
507 const Frame frame = stack.frames().at(0);
508 QCOMPARE(frame.functionName(), QString("_Exit"));
511 const Frame frame = stack.frames().at(1);
512 QCOMPARE(frame.functionName(), QString("exit"));
515 const Frame frame = stack.frames().at(2);
516 QCOMPARE(frame.functionName(), QString("(below main)"));
521 const Stack stack = error.stacks().last();
522 QCOMPARE(stack.line(), qint64(-1));
523 QCOMPARE(stack.frames().count(), 1);
525 const Frame frame = stack.frames().first();
526 QCOMPARE(frame.functionName(), QString("main"));
527 QCOMPARE(frame.line(), 2);
529 QCOMPARE(frame.object(), binary);
530 QCOMPARE(frame.file(), QLatin1String("main.cpp"));
531 QCOMPARE(QDir::cleanPath(frame.directory()), srcDir);
535 void TestRunner::free1()
537 const QString app("free1");
538 const QString binary = runTestBinary(app + QDir::separator() + app);
539 const QString srcDir = srcDirForApp(app);
541 QVERIFY(m_logMessages.isEmpty());
543 QCOMPARE(m_errors.count(), 1);
544 const Error error = m_errors.first();
545 QCOMPARE(error.kind(), int(InvalidFree));
546 QCOMPARE(error.stacks().count(), 2);
549 const Stack stack = error.stacks().first();
550 QCOMPARE(stack.line(), qint64(-1));
551 QCOMPARE(stack.frames().count(), 2);
554 const Frame frame = stack.frames().first();
555 QCOMPARE(frame.functionName(), QString("operator delete(void*)"));
558 const Frame frame = stack.frames().last();
559 QCOMPARE(frame.functionName(), QString("main"));
560 QCOMPARE(frame.line(), 7);
562 QCOMPARE(frame.object(), binary);
563 QCOMPARE(frame.file(), QLatin1String("main.cpp"));
564 QCOMPARE(QDir::cleanPath(frame.directory()), srcDir);
569 const Stack stack = error.stacks().last();
570 QCOMPARE(stack.line(), qint64(-1));
571 QCOMPARE(stack.frames().count(), 2);
575 const Frame frame = stack.frames().first();
576 QCOMPARE(frame.functionName(), QString("operator delete(void*)"));
579 const Frame frame = stack.frames().last();
580 QCOMPARE(frame.functionName(), QString("main"));
581 QCOMPARE(frame.line(), 6);
583 QCOMPARE(frame.object(), binary);
584 QCOMPARE(frame.file(), QLatin1String("main.cpp"));
585 QCOMPARE(QDir::cleanPath(frame.directory()), srcDir);
590 void TestRunner::free2()
592 const QString app("free2");
593 const QString binary = runTestBinary(app + QDir::separator() + app);
594 const QString srcDir = srcDirForApp(app);
596 QVERIFY(m_logMessages.isEmpty());
598 QCOMPARE(m_errors.count(), 1);
599 const Error error = m_errors.first();
600 QCOMPARE(error.kind(), int(MismatchedFree));
601 QCOMPARE(error.stacks().count(), 2);
604 const Stack stack = error.stacks().first();
605 QCOMPARE(stack.line(), qint64(-1));
606 QCOMPARE(stack.frames().count(), 2);
609 const Frame frame = stack.frames().first();
610 QCOMPARE(frame.functionName(), QString("free"));
613 const Frame frame = stack.frames().last();
614 QCOMPARE(frame.functionName(), QString("main"));
615 QCOMPARE(frame.line(), 6);
617 QCOMPARE(frame.object(), binary);
618 QCOMPARE(frame.file(), QLatin1String("main.cpp"));
619 QCOMPARE(QDir::cleanPath(frame.directory()), srcDir);
624 const Stack stack = error.stacks().last();
625 QCOMPARE(stack.line(), qint64(-1));
626 QCOMPARE(stack.frames().count(), 2);
630 const Frame frame = stack.frames().first();
631 QCOMPARE(frame.functionName(), QString("operator new(unsigned long)"));
634 const Frame frame = stack.frames().last();
635 QCOMPARE(frame.functionName(), QString("main"));
636 QCOMPARE(frame.line(), 5);
638 QCOMPARE(frame.object(), binary);
639 QCOMPARE(frame.file(), QLatin1String("main.cpp"));
640 QCOMPARE(QDir::cleanPath(frame.directory()), srcDir);
645 void TestRunner::invalidjump()
647 const QString app("invalidjump");
648 m_expectCrash = true;
649 const QString binary = runTestBinary(app + QDir::separator() + app);
650 const QString srcDir = srcDirForApp(app);
652 QVERIFY(m_logMessages.isEmpty());
654 QCOMPARE(m_errors.count(), 1);
655 const Error error = m_errors.first();
656 QCOMPARE(error.kind(), int(InvalidJump));
657 QCOMPARE(error.stacks().count(), 1);
658 const Stack stack = error.stacks().first();
659 QCOMPARE(stack.line(), qint64(-1));
660 QCOMPARE(stack.frames().count(), 2);
661 QVERIFY(!stack.auxWhat().isEmpty());
663 const Frame frame = stack.frames().at(0);
664 QCOMPARE(frame.instructionPointer(), quint64(0));
667 const Frame frame = stack.frames().at(1);
668 QCOMPARE(frame.functionName(), QString("(below main)"));
673 void TestRunner::overlap()
675 const QString app("overlap");
676 m_expectCrash = true;
677 const QString binary = runTestBinary(app + QDir::separator() + app);
678 const QString srcDir = srcDirForApp(app);
680 QVERIFY(m_logMessages.isEmpty());
682 QCOMPARE(m_errors.count(), 1);
683 const Error error = m_errors.first();
684 QCOMPARE(error.kind(), int(Overlap));
685 QCOMPARE(error.stacks().count(), 1);
686 const Stack stack = error.stacks().first();
687 QCOMPARE(stack.line(), qint64(-1));
688 QCOMPARE(stack.frames().count(), 2);
690 const Frame frame = stack.frames().at(0);
691 QCOMPARE(frame.functionName(), QString("memcpy"));
694 const Frame frame = stack.frames().last();
695 QCOMPARE(frame.functionName(), QString("main"));
696 QCOMPARE(frame.line(), 6);
698 QCOMPARE(frame.object(), binary);
699 QCOMPARE(frame.file(), QLatin1String("main.cpp"));
700 QCOMPARE(QDir::cleanPath(frame.directory()), srcDir);