From 9e10e11c9c77c7eb20c4fdf8e4b8ce285c18d62b Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 19 Oct 2009 16:44:07 +0200 Subject: [PATCH] CDB: Add further checking to avoid invalid set asserts. Clear a failed call. _HAS_ITERATOR_DEBUGGING can unfortunately not be turned off as it is not binary compatible with other code. --- share/qtcreator/gdbmacros/gdbmacros.cpp | 8 + share/qtcreator/gdbmacros/test/main.cpp | 191 ++++++++++++++----- src/plugins/debugger/cdb/cdbdumperhelper.cpp | 8 +- 3 files changed, 157 insertions(+), 50 deletions(-) diff --git a/share/qtcreator/gdbmacros/gdbmacros.cpp b/share/qtcreator/gdbmacros/gdbmacros.cpp index c3c0033ed81..09051086adf 100644 --- a/share/qtcreator/gdbmacros/gdbmacros.cpp +++ b/share/qtcreator/gdbmacros/gdbmacros.cpp @@ -3178,6 +3178,14 @@ static void qDumpStdSetHelper(QDumper &d) const int nn = set.size(); if (nn < 0) return; +#ifdef Q_CC_MSVC + // This set has a head element pointer: + // "{ base class ; HeadType *_MyHead ; unsigned int _MySize }", + // which is valid even if the set is empty. Check that to avoid iterator asserts. + const void *headPtrAddress = addOffset(&set, sizeof(DummyType) - sizeof(unsigned int) - sizeof(void*)); + if (const void *headPtr = deref(headPtrAddress)) + qCheckAccess(headPtr); +#endif Q_TYPENAME DummyType::const_iterator it = set.begin(); const Q_TYPENAME DummyType::const_iterator cend = set.end(); for (int i = 0; i < nn && i < 10 && it != cend; ++i, ++it) diff --git a/share/qtcreator/gdbmacros/test/main.cpp b/share/qtcreator/gdbmacros/test/main.cpp index 28dea56f762..63d47a53df3 100644 --- a/share/qtcreator/gdbmacros/test/main.cpp +++ b/share/qtcreator/gdbmacros/test/main.cpp @@ -48,13 +48,32 @@ // Test uninitialized variables allocing memory bool optTestUninitialized = false; +bool optTestAll = false; +bool optEmptyContainers = false; +unsigned optVerbose = 0; +// Provide address of type of be tested. +// When testing unitialized memory, allocate at random. template inline T* testAddress(T* in) { - return optTestUninitialized ? - (reinterpret_cast(new char[sizeof(T)])) - : in; + unsigned char *mem = 0; + if (optTestUninitialized) { + mem = new unsigned char[sizeof(T)]; + for (int i = 0; i < sizeof(T); i++) { + mem[i] = char(rand() % 255u); + } + } else { + mem = reinterpret_cast(in); + } + if (optVerbose) { + for (int i = 0; i < sizeof(T); i++) { + unsigned int b = mem[i]; + printf("%2d %2x %3d\n", i, b, b); + } + fflush(stdout); + } + return reinterpret_cast(mem); } /* Test program for Dumper development/porting. @@ -175,8 +194,10 @@ static int dumpQMapIntInt() QMap test; QMapNode mapNode; const int valueOffset = (char*)&(mapNode.value) - (char*)&mapNode; - test.insert(42, 43); - test.insert(43, 44); + if (!optEmptyContainers) { + test.insert(42, 43); + test.insert(43, 44); + } prepareInBuffer("QMap", "local.qmapintint", "local.qmapintint", "int@int"); qDumpObjectData440(2, 42, testAddress(&test), 1, sizeof(int), sizeof(int), sizeof(mapNode), valueOffset); fputs(qDumpOutBuffer, stdout); @@ -189,8 +210,10 @@ static int dumpQMapIntString() QMap test; QMapNode mapNode; const int valueOffset = (char*)&(mapNode.value) - (char*)&mapNode; - test.insert(42, QLatin1String("fortytwo")); - test.insert(43, QLatin1String("fortytree")); + if (!optEmptyContainers) { + test.insert(42, QLatin1String("fortytwo")); + test.insert(43, QLatin1String("fortytree")); + } prepareInBuffer("QMap", "local.qmapintqstring", "local.qmapintqstring", "int@QString"); qDumpObjectData440(2, 42, testAddress(&test), 1, sizeof(int), sizeof(QString), sizeof(mapNode), valueOffset); fputs(qDumpOutBuffer, stdout); @@ -201,8 +224,10 @@ static int dumpQMapIntString() static int dumpQSetInt() { QSet test; - test.insert(42); - test.insert(43); + if (!optEmptyContainers) { + test.insert(42); + test.insert(43); + } prepareInBuffer("QSet", "local.qsetint", "local.qsetint", "int"); qDumpObjectData440(2, 42, testAddress(&test), 1, sizeof(int), 0, 0, 0); fputs(qDumpOutBuffer, stdout); @@ -216,9 +241,11 @@ static int dumpQMapQStringString() QMap test; QMapNode mapNode; const int valueOffset = (char*)&(mapNode.value) - (char*)&mapNode; - test.insert(QLatin1String("42s"), QLatin1String("fortytwo")); - test.insert(QLatin1String("423"), QLatin1String("fortytree")); - prepareInBuffer("QMap", "local.qmapqstringqstring", "local.qmapqstringqstring", "QString@QString"); + if (!optEmptyContainers) { + test.insert(QLatin1String("42s"), QLatin1String("fortytwo")); + test.insert(QLatin1String("423"), QLatin1String("fortytree")); + } + prepareInBuffer("QMap", "local.qmapqstringqstring", "local.qmapqstringqstring", "QString@QString"); qDumpObjectData440(2, 42, testAddress(&test), 1, sizeof(QString), sizeof(QString), sizeof(mapNode), valueOffset); fputs(qDumpOutBuffer, stdout); fputc('\n', stdout); @@ -278,8 +305,10 @@ static int dumpStdWString() static int dumpStdStringList() { std::list test; - test.push_back("item1"); - test.push_back("item2"); + if (!optEmptyContainers) { + test.push_back("item1"); + test.push_back("item2"); + } prepareInBuffer("std::list", "local.stringlist", "local.stringlist", "std::string"); qDumpObjectData440(2, 42, testAddress(&test), 1, sizeof(std::string), sizeof(std::list::allocator_type), 0, 0); fputs(qDumpOutBuffer, stdout); @@ -290,8 +319,10 @@ static int dumpStdStringList() static int dumpStdStringQList() { QList test; - test.push_back("item1"); - test.push_back("item2"); + if (!optEmptyContainers) { + test.push_back("item1"); + test.push_back("item2"); + } prepareInBuffer("QList", "local.stringqlist", "local.stringqlist", "std::string"); qDumpObjectData440(2, 42, testAddress(&test), 1, sizeof(std::string), 0, 0, 0); fputs(qDumpOutBuffer, stdout); @@ -302,8 +333,10 @@ static int dumpStdStringQList() static int dumpStdIntList() { std::list test; - test.push_back(1); - test.push_back(2); + if (!optEmptyContainers) { + test.push_back(1); + test.push_back(2); + } prepareInBuffer("std::list", "local.intlist", "local.intlist", "int"); qDumpObjectData440(2, 42, testAddress(&test), 1, sizeof(int), sizeof(std::list::allocator_type), 0, 0); fputs(qDumpOutBuffer, stdout); @@ -314,8 +347,10 @@ static int dumpStdIntList() static int dumpStdIntVector() { std::vector test; - test.push_back(1); - test.push_back(2); + if (!optEmptyContainers) { + test.push_back(1); + test.push_back(2); + } prepareInBuffer("std::vector", "local.intvector", "local.intvector", "int"); qDumpObjectData440(2, 42, testAddress(&test), 1, sizeof(int), sizeof(std::list::allocator_type), 0, 0); fputs(qDumpOutBuffer, stdout); @@ -326,8 +361,10 @@ static int dumpStdIntVector() static int dumpStdStringVector() { std::vector test; - test.push_back("item1"); - test.push_back("item2"); + if (!optEmptyContainers) { + test.push_back("item1"); + test.push_back("item2"); + } prepareInBuffer("std::vector", "local.stringvector", "local.stringvector", "std::string"); qDumpObjectData440(2, 42, testAddress(&test), 1, sizeof(std::string), sizeof(std::list::allocator_type), 0, 0); fputs(qDumpOutBuffer, stdout); @@ -338,8 +375,10 @@ static int dumpStdStringVector() static int dumpStdWStringVector() { std::vector test; - test.push_back(L"item1"); - test.push_back(L"item2"); + if (!optEmptyContainers) { + test.push_back(L"item1"); + test.push_back(L"item2"); + } prepareInBuffer("std::vector", "local.wstringvector", "local.wstringvector", "std::wstring"); qDumpObjectData440(2, 42, testAddress(&test), 1, sizeof(std::wstring), sizeof(std::list::allocator_type), 0, 0); fputs(qDumpOutBuffer, stdout); @@ -350,8 +389,10 @@ static int dumpStdWStringVector() static int dumpStdIntSet() { std::set test; - test.insert(1); - test.insert(2); + if (!optEmptyContainers) { + test.insert(1); + test.insert(2); + } prepareInBuffer("std::set", "local.intset", "local.intset", "int"); qDumpObjectData440(2, 42, testAddress(&test), 1, sizeof(int), sizeof(std::list::allocator_type), 0, 0); fputs(qDumpOutBuffer, stdout); @@ -362,8 +403,10 @@ static int dumpStdIntSet() static int dumpStdStringSet() { std::set test; - test.insert("item1"); - test.insert("item2"); + if (!optEmptyContainers) { + test.insert("item1"); + test.insert("item2"); + } prepareInBuffer("std::set", "local.stringset", "local.stringset", "std::string"); qDumpObjectData440(2, 42, testAddress(&test), 1, sizeof(std::string), sizeof(std::list::allocator_type), 0, 0); fputs(qDumpOutBuffer, stdout); @@ -374,8 +417,10 @@ static int dumpStdStringSet() static int dumpStdQStringSet() { std::set test; - test.insert(QLatin1String("item1")); - test.insert(QLatin1String("item2")); + if (!optEmptyContainers) { + test.insert(QLatin1String("item1")); + test.insert(QLatin1String("item2")); + } prepareInBuffer("std::set", "local.stringset", "local.stringset", "QString"); qDumpObjectData440(2, 42, testAddress(&test), 1, sizeof(QString), sizeof(std::list::allocator_type), 0, 0); fputs(qDumpOutBuffer, stdout); @@ -385,9 +430,11 @@ static int dumpStdQStringSet() static int dumpStdMapIntString() { - std::map test; + std::map test; std::map::value_type entry(42, std::string("fortytwo")); - test.insert(entry); + if (!optEmptyContainers) { + test.insert(entry); + } const int valueOffset = (char*)&(entry.second) - (char*)&entry; prepareInBuffer("std::map", "local.stdmapintstring", "local.stdmapintstring", "int@std::basic_string,std::allocator >@std::less@std::allocator,std::allocator > > >"); @@ -402,7 +449,9 @@ static int dumpStdMapStringString() typedef std::map TestType; TestType test; const TestType::value_type entry("K", "V"); - test.insert(entry); + if (!optEmptyContainers) { + test.insert(entry); + } const int valueOffset = (char*)&(entry.second) - (char*)&entry; prepareInBuffer("std::map", "local.stdmapstringstring", "local.stdmapstringstring", "std::basic_string,std::allocator >@std::basic_string,std::allocator >@std::less@std::allocator,std::allocator >,std::basic_string,std::allocator > > >"); @@ -502,6 +551,23 @@ static TypeDumpFunctionMap registerTypes() return rc; } +static void usage(const char *b, const TypeDumpFunctionMap &tdm) +{ + printf("Usage: %s [-v][-u][-e] \n", b); + printf("Usage: %s [-v][-u][-e] -a excluded_type1 \n", b); + printf("Options: -u Test uninitialized memory\n"); + printf(" -e Empty containers\n"); + printf(" -v Verbose\n"); + printf(" -a Test all available types\n"); + printf("Supported types: "); + const TypeDumpFunctionMap::const_iterator cend = tdm.constEnd(); + for (TypeDumpFunctionMap::const_iterator it = tdm.constBegin(); it != cend; ++it) { + fputs(qPrintable(it.key()), stdout); + fputc(' ', stdout); + } + fputc('\n', stdout); +} + int main(int argc, char *argv[]) { printf("\nQt Creator Debugging Helper testing tool\n\n"); @@ -515,30 +581,57 @@ int main(int argc, char *argv[]) const TypeDumpFunctionMap::const_iterator cend = tdm.constEnd(); if (argc < 2) { - printf("Usage: %s [-a]| \n", argv[0]); - printf("Supported types: "); - for (TypeDumpFunctionMap::const_iterator it = tdm.constBegin(); it != cend; ++it) { - fputs(qPrintable(it.key()), stdout); - fputc(' ', stdout); - } - fputc('\n', stdout); + usage(argv[0], tdm); return 0; } - + // Parse args + QStringList tests; + for (int a = 1; a < argc; a++) { + const char *arg = argv[a]; + if (arg[0] == '-') { + switch (arg[1]) { + case 'a': + optTestAll = true; + break; + case 'u': + optTestUninitialized = true; + break; + case 'v': + optVerbose++; + break; + case 'e': + optEmptyContainers = true; + break; + default: + fprintf(stderr, "Invalid option %s\n", arg); + usage(argv[0], tdm); + return -1; + } + } else { + tests.push_back(QLatin1String(arg)); + } + } + // Go int rc = 0; - if (argc == 2 && !qstrcmp(argv[1], "-a")) { + if (optTestAll) { for (TypeDumpFunctionMap::const_iterator it = tdm.constBegin(); it != cend; ++it) { - printf("\nTesting: %s\n", qPrintable(it.key())); - rc += (*it.value())(); + const QString test = it.key(); + if (tests.contains(test)) { + printf("\nSkipping: %s\n", qPrintable(test)); + } else { + printf("\nTesting: %s\n", qPrintable(test)); + rc += (*it.value())(); + if (optTestUninitialized) + printf("Survived: %s\n", qPrintable(test)); + } } } else { - for (int i = 1; i < argc; i++) { - const char *arg = argv[i]; - printf("\nTesting: %s\n", arg); - const TypeDumpFunctionMap::const_iterator it = tdm.constFind(QLatin1String(arg)); + foreach(const QString &test, tests) { + printf("\nTesting: %s\n", qPrintable(test)); + const TypeDumpFunctionMap::const_iterator it = tdm.constFind(test); if (it == cend) { rc = -1; - fprintf(stderr, "\nUnhandled type: %s\n", argv[i]); + fprintf(stderr, "\nUnhandled type: %s\n", qPrintable(test)); } else { rc = (*it.value())(); } diff --git a/src/plugins/debugger/cdb/cdbdumperhelper.cpp b/src/plugins/debugger/cdb/cdbdumperhelper.cpp index 52b4558772b..2269aab42cd 100644 --- a/src/plugins/debugger/cdb/cdbdumperhelper.cpp +++ b/src/plugins/debugger/cdb/cdbdumperhelper.cpp @@ -563,8 +563,14 @@ CdbDumperHelper::CallResult if (!writeToDebuggee(m_cif->debugDataSpaces, inBuffer, m_inBufferAddress, errorMessage)) return CallFailed; } - if (!CdbDebugEnginePrivate::executeDebuggerCommand(m_cif->debugControl, callCmd, errorMessage)) + if (!CdbDebugEnginePrivate::executeDebuggerCommand(m_cif->debugControl, callCmd, errorMessage)) { + // Clear the outstanding call in case we triggered a debug library assert with a message box + QString clearError; + if (!CdbDebugEnginePrivate::executeDebuggerCommand(m_cif->debugControl, QLatin1String(".call /c"), &clearError)) { + *errorMessage += QString::fromLatin1("/Unable to clear call %1").arg(clearError); + } return CallSyntaxError; + } // Set up call and a temporary breakpoint after it. // Try to skip debuggee crash exceptions and dumper exceptions // by using 'gN' (go not handled -> pass handling to dumper __try/__catch block)