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 (qt-info@nokia.com)
11 ** No Commercial Usage
13 ** This file contains pre-release code and may not be distributed.
14 ** You may use this file in accordance with the terms and conditions
15 ** contained in the Technology Preview License Agreement accompanying
18 ** GNU Lesser General Public License Usage
20 ** Alternatively, this file may be used under the terms of the GNU Lesser
21 ** General Public License version 2.1 as published by the Free Software
22 ** Foundation and appearing in the file LICENSE.LGPL included in the
23 ** packaging of this file. Please review the following information to
24 ** ensure the GNU Lesser General Public License version 2.1 requirements
25 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
27 ** In addition, as a special exception, Nokia gives you certain additional
28 ** rights. These rights are described in the Nokia Qt LGPL Exception
29 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
31 ** If you have questions regarding the use of this file, please contact
32 ** Nokia at qt-info@nokia.com.
34 **************************************************************************/
36 #include "testrunner.h"
38 #include <valgrind/xmlprotocol/frame.h>
39 #include <valgrind/xmlprotocol/stack.h>
40 #include <valgrind/xmlprotocol/suppression.h>
41 #include <valgrind/xmlprotocol/threadedparser.h>
42 #include <valgrind/xmlprotocol/parser.h>
43 #include <valgrind/memcheck/memcheckrunner.h>
50 const QString appSrcDir(TESTRUNNER_SRC_DIR);
51 const QString appBinDir(TESTRUNNER_APP_DIR);
53 QString srcDirForApp(const QString &app)
55 return appSrcDir + QDir::separator() + app;
58 QTEST_MAIN(Valgrind::TestRunner)
60 using namespace Valgrind;
61 using namespace Valgrind::XmlProtocol;
62 using namespace Valgrind::Memcheck;
64 //BEGIN Test Helpers and boilterplate code
66 TestRunner::TestRunner(QObject *parent)
71 qRegisterMetaType<Error>();
74 QString TestRunner::runTestBinary(const QString &binary, const QStringList &vArgs)
76 const QString binPath = appBinDir + QDir::separator() + binary;
77 Q_ASSERT(QFileInfo(binPath).isExecutable());
78 m_runner->setValgrindArguments(QStringList() << "--num-callers=50" << "--track-origins=yes" << vArgs);
79 m_runner->setDebuggeeExecutable(binPath);
81 m_runner->waitForFinished();
85 void TestRunner::logMessageReceived(const QByteArray &message)
87 qDebug() << "log message received:" << message;
88 m_logMessages << message;
91 void TestRunner::internalError(const QString &error)
94 QFAIL(qPrintable(error));
96 qDebug() << "expected crash:" << error;
99 void TestRunner::error(const Error &error)
104 void TestRunner::cleanup()
113 m_logMessages.clear();
115 m_expectCrash = false;
118 void TestRunner::init()
120 Q_ASSERT(m_logMessages.isEmpty());
123 m_runner = new MemcheckRunner;
124 m_runner->setValgrindExecutable(QLatin1String("valgrind"));
125 m_runner->setProcessChannelMode(QProcess::ForwardedChannels);
126 connect(m_runner, SIGNAL(logMessageReceived(QByteArray)),
127 this, SLOT(logMessageReceived(QByteArray)));
128 connect(m_runner, SIGNAL(processErrorReceived(QString, QProcess::ProcessError)),
129 this, SLOT(internalError(QString)));
131 m_parser = new ThreadedParser;
132 connect(m_parser, SIGNAL(internalError(QString)),
133 this, SLOT(internalError(QString)));
134 connect(m_parser, SIGNAL(error(Valgrind::XmlProtocol::Error)),
135 this, SLOT(error(Valgrind::XmlProtocol::Error)));
137 m_runner->setParser(m_parser);
140 //BEGIN: Actual test cases
142 void TestRunner::testLeak1()
144 const QString binary = runTestBinary(QLatin1String("leak1/leak1"));
146 QVERIFY(m_logMessages.isEmpty());
148 QCOMPARE(m_errors.count(), 1);
149 const Error error = m_errors.first();
150 QCOMPARE(error.kind(), int(Leak_DefinitelyLost));
151 QCOMPARE(error.leakedBlocks(), qint64(1));
152 QCOMPARE(error.leakedBytes(), quint64(8));
153 QCOMPARE(error.stacks().count(), 1);
154 const Stack stack = error.stacks().first();
155 QCOMPARE(stack.line(), qint64(-1));
156 QCOMPARE(stack.frames().count(), 2);
158 const Frame frame = stack.frames().at(0);
159 QCOMPARE(frame.functionName(), QString("operator new(unsigned long)"));
162 const Frame frame = stack.frames().at(1);
163 QCOMPARE(frame.functionName(), QString("main"));
164 QCOMPARE(frame.line(), 5);
166 QCOMPARE(frame.object(), binary);
167 QCOMPARE(frame.file(), QLatin1String("main.cpp"));
168 QCOMPARE(QDir::cleanPath(frame.directory()), srcDirForApp("leak1"));
172 void TestRunner::testLeak2()
174 const QString binary = runTestBinary(QLatin1String("leak2/leak2"));
176 QVERIFY(m_logMessages.isEmpty());
178 QCOMPARE(m_errors.count(), 1);
179 const Error error = m_errors.first();
180 QCOMPARE(error.kind(), int(Leak_PossiblyLost));
181 QCOMPARE(error.leakedBlocks(), qint64(1));
182 QCOMPARE(error.leakedBytes(), quint64(5));
183 QCOMPARE(error.stacks().count(), 1);
184 const Stack stack = error.stacks().first();
185 QCOMPARE(stack.line(), qint64(-1));
186 QCOMPARE(stack.frames().count(), 3);
188 const Frame frame = stack.frames().at(0);
189 QCOMPARE(frame.functionName(), QString("malloc"));
192 const Frame frame = stack.frames().at(1);
193 QCOMPARE(frame.functionName(), QString("strdup"));
196 const Frame frame = stack.frames().at(2);
197 QCOMPARE(frame.functionName(), QString("main"));
198 QCOMPARE(frame.line(), 7);
200 QCOMPARE(frame.object(), binary);
201 QCOMPARE(frame.file(), QLatin1String("main.cpp"));
202 QCOMPARE(QDir::cleanPath(frame.directory()), srcDirForApp("leak2"));
206 void TestRunner::testLeak3()
208 const QString binary = runTestBinary(QLatin1String("leak3/leak3"), QStringList() << "--show-reachable=yes");
210 QVERIFY(m_logMessages.isEmpty());
212 QCOMPARE(m_errors.count(), 1);
213 const Error error = m_errors.first();
214 QCOMPARE(error.kind(), int(Leak_StillReachable));
215 QCOMPARE(error.leakedBlocks(), qint64(1));
216 QCOMPARE(error.leakedBytes(), quint64(5));
217 QCOMPARE(error.stacks().count(), 1);
218 const Stack stack = error.stacks().first();
219 QCOMPARE(stack.line(), qint64(-1));
220 QCOMPARE(stack.frames().count(), 3);
222 const Frame frame = stack.frames().at(0);
223 QCOMPARE(frame.functionName(), QString("malloc"));
226 const Frame frame = stack.frames().at(1);
227 QCOMPARE(frame.functionName(), QString("strdup"));
230 const Frame frame = stack.frames().at(2);
231 QCOMPARE(frame.functionName(), QString("main"));
232 QCOMPARE(frame.line(), 7);
234 QCOMPARE(frame.object(), binary);
235 QCOMPARE(frame.file(), QLatin1String("main.cpp"));
236 QCOMPARE(QDir::cleanPath(frame.directory()), srcDirForApp("leak3"));
240 void TestRunner::testLeak4()
242 const QString app("leak4");
243 const QString binary = runTestBinary(app + QDir::separator() + app,
244 QStringList() << "--show-reachable=yes");
245 const QString srcDir = srcDirForApp("leak4");
247 QVERIFY(m_logMessages.isEmpty());
249 QCOMPARE(m_errors.count(), 2);
252 const Error error = m_errors.first();
253 QCOMPARE(error.kind(), int(Leak_IndirectlyLost));
254 QCOMPARE(error.leakedBlocks(), qint64(1));
255 QCOMPARE(error.leakedBytes(), quint64(8));
256 QCOMPARE(error.stacks().count(), 1);
257 const Stack stack = error.stacks().first();
258 QCOMPARE(stack.line(), qint64(-1));
259 QCOMPARE(stack.frames().count(), 3);
261 const Frame frame = stack.frames().at(0);
262 QCOMPARE(frame.functionName(), QString("operator new(unsigned long)"));
265 const Frame frame = stack.frames().at(2);
266 QCOMPARE(frame.functionName(), QString("main"));
267 QCOMPARE(frame.line(), 13);
269 QCOMPARE(frame.object(), binary);
270 QCOMPARE(frame.file(), QLatin1String("main.cpp"));
271 QCOMPARE(QDir::cleanPath(frame.directory()), srcDir);
274 const Frame frame = stack.frames().at(1);
275 QCOMPARE(frame.functionName(), QString("foo::foo()"));
276 QCOMPARE(frame.line(), 5);
278 QCOMPARE(frame.object(), binary);
279 QCOMPARE(frame.file(), QLatin1String("main.cpp"));
280 QCOMPARE(QDir::cleanPath(frame.directory()), srcDir);
283 const Frame frame = stack.frames().at(2);
284 QCOMPARE(frame.functionName(), QString("main"));
285 QCOMPARE(frame.line(), 13);
287 QCOMPARE(frame.object(), binary);
288 QCOMPARE(frame.file(), QLatin1String("main.cpp"));
289 QCOMPARE(QDir::cleanPath(frame.directory()), srcDir);
294 const Error error = m_errors.last();
295 QCOMPARE(error.kind(), int(Leak_DefinitelyLost));
296 QCOMPARE(error.leakedBlocks(), qint64(1));
297 QCOMPARE(error.leakedBytes(), quint64(16));
298 QCOMPARE(error.stacks().count(), 1);
299 const Stack stack = error.stacks().first();
300 QCOMPARE(stack.line(), qint64(-1));
301 QCOMPARE(stack.frames().count(), 2);
303 const Frame frame = stack.frames().at(0);
304 QCOMPARE(frame.functionName(), QString("operator new(unsigned long)"));
307 const Frame frame = stack.frames().at(1);
308 QCOMPARE(frame.functionName(), QString("main"));
309 QCOMPARE(frame.line(), 13);
311 QCOMPARE(frame.object(), binary);
312 QCOMPARE(frame.file(), QLatin1String("main.cpp"));
313 QCOMPARE(QDir::cleanPath(frame.directory()), srcDir);
318 void TestRunner::uninit1()
320 const QString app("uninit1");
321 const QString binary = runTestBinary(app + QDir::separator() + app);
322 const QString srcDir = srcDirForApp(app);
324 QVERIFY(m_logMessages.isEmpty());
326 QCOMPARE(m_errors.count(), 1);
327 const Error error = m_errors.first();
328 QCOMPARE(error.kind(), int(UninitCondition));
329 QCOMPARE(error.stacks().count(), 2);
332 const Stack stack = error.stacks().first();
333 QCOMPARE(stack.line(), qint64(-1));
334 QCOMPARE(stack.frames().count(), 1);
336 const Frame frame = stack.frames().first();
337 QCOMPARE(frame.functionName(), QString("main"));
338 QCOMPARE(frame.line(), 4);
340 QCOMPARE(frame.object(), binary);
341 QCOMPARE(frame.file(), QLatin1String("main.cpp"));
342 QCOMPARE(QDir::cleanPath(frame.directory()), srcDir);
346 const Stack stack = error.stacks().last();
347 QCOMPARE(stack.line(), qint64(-1));
348 QCOMPARE(stack.frames().count(), 1);
350 const Frame frame = stack.frames().first();
351 QCOMPARE(frame.functionName(), QString("main"));
352 QCOMPARE(frame.line(), 2);
354 QCOMPARE(frame.object(), binary);
355 QCOMPARE(frame.file(), QLatin1String("main.cpp"));
356 QCOMPARE(QDir::cleanPath(frame.directory()), srcDir);
360 void TestRunner::uninit2()
362 const QString app("uninit2");
363 m_expectCrash = true;
364 const QString binary = runTestBinary(app + QDir::separator() + app);
365 const QString srcDir = srcDirForApp(app);
367 QVERIFY(m_logMessages.isEmpty());
369 QCOMPARE(m_errors.count(), 2);
372 const Error error = m_errors.first();
373 QCOMPARE(error.kind(), int(UninitValue));
374 QCOMPARE(error.stacks().count(), 2);
377 const Stack stack = error.stacks().first();
378 QCOMPARE(stack.line(), qint64(-1));
379 QCOMPARE(stack.frames().count(), 1);
381 const Frame frame = stack.frames().first();
382 QCOMPARE(frame.functionName(), QString("main"));
383 QCOMPARE(frame.line(), 4);
385 QCOMPARE(frame.object(), binary);
386 QCOMPARE(frame.file(), QLatin1String("main.cpp"));
387 QCOMPARE(QDir::cleanPath(frame.directory()), srcDir);
391 const Stack stack = error.stacks().last();
392 QCOMPARE(stack.line(), qint64(-1));
393 QCOMPARE(stack.frames().count(), 1);
395 const Frame frame = stack.frames().first();
396 QCOMPARE(frame.functionName(), QString("main"));
397 QCOMPARE(frame.line(), 2);
399 QCOMPARE(frame.object(), binary);
400 QCOMPARE(frame.file(), QLatin1String("main.cpp"));
401 QCOMPARE(QDir::cleanPath(frame.directory()), srcDir);
406 const Error error = m_errors.last();
407 QCOMPARE(error.kind(), int(InvalidWrite));
408 QCOMPARE(error.stacks().count(), 1);
410 const Stack stack = error.stacks().first();
411 QCOMPARE(stack.line(), qint64(-1));
412 QCOMPARE(stack.frames().count(), 1);
414 const Frame frame = stack.frames().first();
415 QCOMPARE(frame.functionName(), QString("main"));
416 QCOMPARE(frame.line(), 4);
418 QCOMPARE(frame.object(), binary);
419 QCOMPARE(frame.file(), QLatin1String("main.cpp"));
420 QCOMPARE(QDir::cleanPath(frame.directory()), srcDir);
424 void TestRunner::uninit3()
426 const QString app("uninit3");
427 m_expectCrash = true;
428 const QString binary = runTestBinary(app + QDir::separator() + app);
429 const QString srcDir = srcDirForApp(app);
431 QVERIFY(m_logMessages.isEmpty());
433 QCOMPARE(m_errors.count(), 2);
436 const Error error = m_errors.first();
437 QCOMPARE(error.kind(), int(UninitValue));
438 QCOMPARE(error.stacks().count(), 2);
441 const Stack stack = error.stacks().first();
442 QCOMPARE(stack.line(), qint64(-1));
443 QCOMPARE(stack.frames().count(), 1);
445 const Frame frame = stack.frames().first();
446 QCOMPARE(frame.functionName(), QString("main"));
447 QCOMPARE(frame.line(), 3);
449 QCOMPARE(frame.object(), binary);
450 QCOMPARE(frame.file(), QLatin1String("main.cpp"));
451 QCOMPARE(QDir::cleanPath(frame.directory()), srcDir);
455 const Stack stack = error.stacks().last();
456 QCOMPARE(stack.line(), qint64(-1));
457 QCOMPARE(stack.frames().count(), 1);
459 const Frame frame = stack.frames().first();
460 QCOMPARE(frame.functionName(), QString("main"));
461 QCOMPARE(frame.line(), 1);
463 QCOMPARE(frame.object(), binary);
464 QCOMPARE(frame.file(), QLatin1String("main.cpp"));
465 QCOMPARE(QDir::cleanPath(frame.directory()), srcDir);
470 const Error error = m_errors.last();
471 QCOMPARE(error.kind(), int(InvalidRead));
472 QCOMPARE(error.stacks().count(), 1);
474 const Stack stack = error.stacks().first();
475 QCOMPARE(stack.line(), qint64(-1));
476 QCOMPARE(stack.frames().count(), 1);
478 const Frame frame = stack.frames().first();
479 QCOMPARE(frame.functionName(), QString("main"));
480 QCOMPARE(frame.line(), 3);
482 QCOMPARE(frame.object(), binary);
483 QCOMPARE(frame.file(), QLatin1String("main.cpp"));
484 QCOMPARE(QDir::cleanPath(frame.directory()), srcDir);
488 void TestRunner::syscall()
490 const QString app("syscall");
491 const QString binary = runTestBinary(app + QDir::separator() + app);
492 const QString srcDir = srcDirForApp(app);
494 QVERIFY(m_logMessages.isEmpty());
496 QCOMPARE(m_errors.count(), 1);
497 const Error error = m_errors.first();
498 QCOMPARE(error.kind(), int(SyscallParam));
499 QCOMPARE(error.stacks().count(), 2);
502 const Stack stack = error.stacks().first();
503 QCOMPARE(stack.line(), qint64(-1));
504 QCOMPARE(stack.frames().count(), 3);
507 ///TODO: is this platform specific?
508 const Frame frame = stack.frames().at(0);
509 QCOMPARE(frame.functionName(), QString("_Exit"));
512 const Frame frame = stack.frames().at(1);
513 QCOMPARE(frame.functionName(), QString("exit"));
516 const Frame frame = stack.frames().at(2);
517 QCOMPARE(frame.functionName(), QString("(below main)"));
522 const Stack stack = error.stacks().last();
523 QCOMPARE(stack.line(), qint64(-1));
524 QCOMPARE(stack.frames().count(), 1);
526 const Frame frame = stack.frames().first();
527 QCOMPARE(frame.functionName(), QString("main"));
528 QCOMPARE(frame.line(), 2);
530 QCOMPARE(frame.object(), binary);
531 QCOMPARE(frame.file(), QLatin1String("main.cpp"));
532 QCOMPARE(QDir::cleanPath(frame.directory()), srcDir);
536 void TestRunner::free1()
538 const QString app("free1");
539 const QString binary = runTestBinary(app + QDir::separator() + app);
540 const QString srcDir = srcDirForApp(app);
542 QVERIFY(m_logMessages.isEmpty());
544 QCOMPARE(m_errors.count(), 1);
545 const Error error = m_errors.first();
546 QCOMPARE(error.kind(), int(InvalidFree));
547 QCOMPARE(error.stacks().count(), 2);
550 const Stack stack = error.stacks().first();
551 QCOMPARE(stack.line(), qint64(-1));
552 QCOMPARE(stack.frames().count(), 2);
555 const Frame frame = stack.frames().first();
556 QCOMPARE(frame.functionName(), QString("operator delete(void*)"));
559 const Frame frame = stack.frames().last();
560 QCOMPARE(frame.functionName(), QString("main"));
561 QCOMPARE(frame.line(), 7);
563 QCOMPARE(frame.object(), binary);
564 QCOMPARE(frame.file(), QLatin1String("main.cpp"));
565 QCOMPARE(QDir::cleanPath(frame.directory()), srcDir);
570 const Stack stack = error.stacks().last();
571 QCOMPARE(stack.line(), qint64(-1));
572 QCOMPARE(stack.frames().count(), 2);
576 const Frame frame = stack.frames().first();
577 QCOMPARE(frame.functionName(), QString("operator delete(void*)"));
580 const Frame frame = stack.frames().last();
581 QCOMPARE(frame.functionName(), QString("main"));
582 QCOMPARE(frame.line(), 6);
584 QCOMPARE(frame.object(), binary);
585 QCOMPARE(frame.file(), QLatin1String("main.cpp"));
586 QCOMPARE(QDir::cleanPath(frame.directory()), srcDir);
591 void TestRunner::free2()
593 const QString app("free2");
594 const QString binary = runTestBinary(app + QDir::separator() + app);
595 const QString srcDir = srcDirForApp(app);
597 QVERIFY(m_logMessages.isEmpty());
599 QCOMPARE(m_errors.count(), 1);
600 const Error error = m_errors.first();
601 QCOMPARE(error.kind(), int(MismatchedFree));
602 QCOMPARE(error.stacks().count(), 2);
605 const Stack stack = error.stacks().first();
606 QCOMPARE(stack.line(), qint64(-1));
607 QCOMPARE(stack.frames().count(), 2);
610 const Frame frame = stack.frames().first();
611 QCOMPARE(frame.functionName(), QString("free"));
614 const Frame frame = stack.frames().last();
615 QCOMPARE(frame.functionName(), QString("main"));
616 QCOMPARE(frame.line(), 6);
618 QCOMPARE(frame.object(), binary);
619 QCOMPARE(frame.file(), QLatin1String("main.cpp"));
620 QCOMPARE(QDir::cleanPath(frame.directory()), srcDir);
625 const Stack stack = error.stacks().last();
626 QCOMPARE(stack.line(), qint64(-1));
627 QCOMPARE(stack.frames().count(), 2);
631 const Frame frame = stack.frames().first();
632 QCOMPARE(frame.functionName(), QString("operator new(unsigned long)"));
635 const Frame frame = stack.frames().last();
636 QCOMPARE(frame.functionName(), QString("main"));
637 QCOMPARE(frame.line(), 5);
639 QCOMPARE(frame.object(), binary);
640 QCOMPARE(frame.file(), QLatin1String("main.cpp"));
641 QCOMPARE(QDir::cleanPath(frame.directory()), srcDir);
646 void TestRunner::invalidjump()
648 const QString app("invalidjump");
649 m_expectCrash = true;
650 const QString binary = runTestBinary(app + QDir::separator() + app);
651 const QString srcDir = srcDirForApp(app);
653 QVERIFY(m_logMessages.isEmpty());
655 QCOMPARE(m_errors.count(), 1);
656 const Error error = m_errors.first();
657 QCOMPARE(error.kind(), int(InvalidJump));
658 QCOMPARE(error.stacks().count(), 1);
659 const Stack stack = error.stacks().first();
660 QCOMPARE(stack.line(), qint64(-1));
661 QCOMPARE(stack.frames().count(), 2);
662 QVERIFY(!stack.auxWhat().isEmpty());
664 const Frame frame = stack.frames().at(0);
665 QCOMPARE(frame.instructionPointer(), quint64(0));
668 const Frame frame = stack.frames().at(1);
669 QCOMPARE(frame.functionName(), QString("(below main)"));
674 void TestRunner::overlap()
676 const QString app("overlap");
677 m_expectCrash = true;
678 const QString binary = runTestBinary(app + QDir::separator() + app);
679 const QString srcDir = srcDirForApp(app);
681 QVERIFY(m_logMessages.isEmpty());
683 QCOMPARE(m_errors.count(), 1);
684 const Error error = m_errors.first();
685 QCOMPARE(error.kind(), int(Overlap));
686 QCOMPARE(error.stacks().count(), 1);
687 const Stack stack = error.stacks().first();
688 QCOMPARE(stack.line(), qint64(-1));
689 QCOMPARE(stack.frames().count(), 2);
691 const Frame frame = stack.frames().at(0);
692 QCOMPARE(frame.functionName(), QString("memcpy"));
695 const Frame frame = stack.frames().last();
696 QCOMPARE(frame.functionName(), QString("main"));
697 QCOMPARE(frame.line(), 6);
699 QCOMPARE(frame.object(), binary);
700 QCOMPARE(frame.file(), QLatin1String("main.cpp"));
701 QCOMPARE(QDir::cleanPath(frame.directory()), srcDir);