diff --git a/share/qtcreator/gdbmacros/gdbmacros.cpp b/share/qtcreator/gdbmacros/gdbmacros.cpp index a265eb9ceda..c464b9435a9 100644 --- a/share/qtcreator/gdbmacros/gdbmacros.cpp +++ b/share/qtcreator/gdbmacros/gdbmacros.cpp @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #include @@ -270,15 +271,45 @@ static bool startsWith(const char *s, const char *t) return true; } +static bool couldBePointer(const void *p) +{ + // we assume valid pointer to be 4-aligned at least. + // So use this check only when this is guaranteed. + const quintptr d = quintptr(p); + qDebug() << "CHECKING : " << p << ((d & 3) == 0 && (d > 1000 || d == 0)); + return (d & 3) == 0 && (d > 1000 || d == 0); +} + // Check memory for read access and provoke segfault if nothing else helps. // On Windows, try to be less crash-prone by checking memory using WinAPI #ifdef Q_OS_WIN -# define qCheckAccess(d) do { if (IsBadReadPtr(d, 1)) return; qProvokeSegFaultHelper = *(char*)d; } while (0) -# define qCheckPointer(d) do { if (d && IsBadReadPtr(d, 1)) return; if (d) qProvokeSegFaultHelper = *(char*)d; } while (0) + +# define qCheckAccess(d) do { \ + if (IsBadReadPtr(d, 1)) \ + return; \ + qProvokeSegFaultHelper = *(char*)d; \ + } while (0) +# define qCheckPointer(d) do { \ + if (d && IsBadReadPtr(d, 1)) \ + return; \ + if (d) qProvokeSegFaultHelper = *(char*)d; \ + } while (0) + #else -# define qCheckAccess(d) do { qProvokeSegFaultHelper = *(char*)d; } while (0) -# define qCheckPointer(d) do { if (d) qProvokeSegFaultHelper = *(char*)d; } while (0) + +# define qCheckAccess(d) do { \ + if (!couldBePointer(d) && d != 0) \ + return; \ + qProvokeSegFaultHelper = *(char*)d; \ + } while (0) +# define qCheckPointer(d) do { \ + if (!couldBePointer(d)) \ + return; \ + if (d) \ + qProvokeSegFaultHelper = *(char*)d; \ + } while (0) + #endif #ifdef QT_NAMESPACE @@ -848,6 +879,7 @@ static void qDumpUnknown(QDumper &d, const char *why = 0) why = DUMPUNKNOWN_MESSAGE; d.putItem("value", why); d.putItem("type", d.outertype); + d.putItem("valuedisabled", "true"); d.putItem("numchild", "0", d.currentChildNumChild); d.disarm(); } @@ -1143,6 +1175,7 @@ static void qDumpQAbstractItemModel(QDumper &d) static void qDumpQByteArray(QDumper &d) { + qCheckAccess(deref(d.data)); const QByteArray &ba = *reinterpret_cast(d.data); if (!ba.isEmpty()) { @@ -1408,10 +1441,11 @@ int hashOffset(bool optimizedIntKey, bool forKey, unsigned keySize, unsigned val static void qDumpQHash(QDumper &d) { - QHashData *h = *reinterpret_cast(d.data); + qCheckAccess(deref(d.data)); const char *keyType = d.templateParameters[0]; const char *valueType = d.templateParameters[1]; + QHashData *h = *reinterpret_cast(d.data); qCheckPointer(h->fakeNext); qCheckPointer(h->buckets); @@ -1515,6 +1549,7 @@ static void qDumpQHashNode(QDumper &d) #if USE_QT_GUI static void qDumpQImage(QDumper &d) { + qCheckAccess(deref(d.data)); const QImage &im = *reinterpret_cast(d.data); d.beginItem("value"); d.put("(").put(im.width()).put("x").put(im.height()).put(")"); @@ -1556,20 +1591,17 @@ static void qDumpQImageData(QDumper &d) static void qDumpQList(QDumper &d) { + qCheckAccess(deref(d.data)); // This uses the knowledge that QList has only a single member // of type union { QListData p; QListData::Data *d; }; const QListData &ldata = *reinterpret_cast(d.data); const QListData::Data *pdata = *reinterpret_cast(d.data); - qCheckAccess(pdata); int nn = ldata.size(); if (nn < 0) return; if (nn > 0) { - qCheckAccess(ldata.d->array); - //qCheckAccess(ldata.d->array[0]); - //qCheckAccess(ldata.d->array[nn - 1]); if (ldata.d->begin < 0) return; if (ldata.d->begin > ldata.d->end) @@ -1578,7 +1610,11 @@ static void qDumpQList(QDumper &d) if (ldata.d->ref._q_value <= 0) return; #endif + qCheckAccess(ldata.d->array); + //qCheckAccess(ldata.d->array[0]); + //qCheckAccess(ldata.d->array[nn - 1]); } + qCheckAccess(pdata); int n = nn; d.putItemCount("value", n); @@ -1635,6 +1671,7 @@ static void qDumpQList(QDumper &d) static void qDumpQLinkedList(QDumper &d) { + qCheckAccess(deref(d.data)); // This uses the knowledge that QLinkedList has only a single member // of type union { QLinkedListData *d; QLinkedListNode *e; }; const QLinkedListData *ldata = @@ -1760,6 +1797,7 @@ static void qDumpQMapNode(QDumper &d) static void qDumpQMap(QDumper &d) { + qCheckAccess(deref(d.data)); QMapData *h = *reinterpret_cast(d.data); const char *keyType = d.templateParameters[0]; const char *valueType = d.templateParameters[1]; @@ -1898,6 +1936,7 @@ static void qDumpQModelIndex(QDumper &d) static void qDumpQObject(QDumper &d) { + qCheckAccess(deref(d.data)); const QObject *ob = reinterpret_cast(d.data); const QMetaObject *mo = ob->metaObject(); d.putItem("value", ob->objectName()); @@ -2147,6 +2186,7 @@ static void qDumpQVariant(QDumper &d, const QVariant *v) static inline void qDumpQVariant(QDumper &d) { + qCheckAccess(deref(d.data)); qDumpQVariant(d, reinterpret_cast(d.data)); } @@ -2772,6 +2812,7 @@ static void qDumpQSharedPointer(QDumper &d) static void qDumpQString(QDumper &d) { + qCheckAccess(deref(d.data)); const QString &str = *reinterpret_cast(d.data); const int size = str.size(); @@ -2796,6 +2837,7 @@ static void qDumpQString(QDumper &d) static void qDumpQStringList(QDumper &d) { + qCheckAccess(deref(d.data)); const QStringList &list = *reinterpret_cast(d.data); int n = list.size(); if (n < 0) @@ -2827,6 +2869,7 @@ static void qDumpQStringList(QDumper &d) static void qDumpQTextCodec(QDumper &d) { + qCheckPointer(deref(d.data)); const QTextCodec &codec = *reinterpret_cast(d.data); d.putItem("value", codec.name()); d.putItem("valueencoded", "1"); @@ -2843,6 +2886,7 @@ static void qDumpQTextCodec(QDumper &d) static void qDumpQVector(QDumper &d) { + qCheckAccess(deref(d.data)); QVectorTypedData *dummy = 0; const unsigned typeddatasize = (char*)(&dummy->array) - (char*)dummy; @@ -3421,6 +3465,8 @@ static void handleProtocolVersion2and3(QDumper &d) #ifndef QT_BOOTSTRAPPED else if (isEqual(type, "QSet")) qDumpQSet(d); + else if (isEqual(type, "QStack")) + qDumpQVector(d); #if QT_VERSION >= 0x040500 else if (isEqual(type, "QSharedPointer")) qDumpQSharedPointer(d); @@ -3596,6 +3642,7 @@ void *qDumpObjectData440( "\""NS"QRectF\"," //"\""NS"QRegion\"," "\""NS"QSet\"," + "\""NS"QStack\"," "\""NS"QString\"," "\""NS"QStringList\"," "\""NS"QTextCodec\"," diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index 9c4f7dda85c..0d6ed3376ce 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -2907,7 +2907,8 @@ void GdbEngine::runDebuggingHelper(const WatchData &data0, bool dumpChildren) WatchData data = data0; // Avoid endless loops created by faulty dumpers - if (m_processedNames.contains(data.iname)) { + QString processedName = QString(_("%1-%2").arg(dumpChildren).arg(data.iname)); + if (m_processedNames.contains(processedName)) { emit gdbInputAvailable(LogStatus, _("").arg(data.iname)); data.setAllUnneeded(); @@ -2916,7 +2917,7 @@ void GdbEngine::runDebuggingHelper(const WatchData &data0, bool dumpChildren) insertData(data); return; } - m_processedNames.insert(data.iname); + m_processedNames.insert(processedName); QByteArray params; QStringList extraArgs; @@ -3427,7 +3428,7 @@ void GdbEngine::handleDebuggingHelperValue2(const GdbResultRecord &record, WatchData childtemplate; setWatchDataType(childtemplate, contents.findChild("childtype")); setWatchDataChildCount(childtemplate, contents.findChild("childnumchild")); - //qDebug() << "DATA:" << data.toString(); + //qDebug() << "CHILD TEMPLATE:" << childtemplate.toString(); qq->watchHandler()->insertData(data); int i = 0; diff --git a/src/plugins/debugger/watchutils.cpp b/src/plugins/debugger/watchutils.cpp index 246c52d58e0..6b6a358455e 100644 --- a/src/plugins/debugger/watchutils.cpp +++ b/src/plugins/debugger/watchutils.cpp @@ -785,24 +785,26 @@ QtDumperHelper::Type QtDumperHelper::specialType(QString s) } else { s = s.mid(namespaceIndex + 2); } - if (s == QLatin1String("QObject")) - return QObjectType; - if (s == QLatin1String("QWidget")) - return QWidgetType; - if (s == QLatin1String("QObjectSlot")) - return QObjectSlotType; - if (s == QLatin1String("QObjectSignal")) - return QObjectSignalType; - if (s == QLatin1String("QVector")) - return QVectorType; if (s == QLatin1String("QAbstractItem")) return QAbstractItemType; if (s == QLatin1String("QMap")) return QMapType; - if (s == QLatin1String("QMultiMap")) - return QMultiMapType; if (s == QLatin1String("QMapNode")) return QMapNodeType; + if (s == QLatin1String("QMultiMap")) + return QMultiMapType; + if (s == QLatin1String("QObject")) + return QObjectType; + if (s == QLatin1String("QObjectSignal")) + return QObjectSignalType; + if (s == QLatin1String("QObjectSlot")) + return QObjectSlotType; + if (s == QLatin1String("QStack")) + return QStackType; + if (s == QLatin1String("QVector")) + return QVectorType; + if (s == QLatin1String("QWidget")) + return QWidgetType; return UnknownType; } @@ -1458,6 +1460,7 @@ void QtDumperHelper::evaluationParameters(const WatchData &data, break; case SupportedType: case QVectorType: + case QStackType: case QObjectType: case QWidgetType: break; diff --git a/src/plugins/debugger/watchutils.h b/src/plugins/debugger/watchutils.h index 46ff17f736e..7c854009813 100644 --- a/src/plugins/debugger/watchutils.h +++ b/src/plugins/debugger/watchutils.h @@ -160,7 +160,7 @@ public: // Below types require special handling QAbstractItemType, QObjectType, QWidgetType, QObjectSlotType, QObjectSignalType, - QVectorType, QMapType, QMultiMapType, QMapNodeType, + QVectorType, QMapType, QMultiMapType, QMapNodeType, QStackType, StdVectorType, StdDequeType, StdSetType, StdMapType, StdStackType, StdStringType }; diff --git a/tests/manual/gdbdebugger/simple/app.cpp b/tests/manual/gdbdebugger/simple/app.cpp index 830efb50a87..3a63d348b8c 100644 --- a/tests/manual/gdbdebugger/simple/app.cpp +++ b/tests/manual/gdbdebugger/simple/app.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -855,6 +856,30 @@ void testQStandardItemModel() +i; } +void testQStack() +{ + QVector bigv; + for (int i = 0; i < 10; ++i) + bigv.append(i); + QStack big; + for (int i = 0; i < 10; ++i) + big.append(i); + QStack plist; + plist.append(new Foo(1)); + plist.append(0); + plist.append(new Foo(2)); + QStack flist; + flist.append(1); + flist.append(2); + flist.append(3); + flist.append(4); + //flist.takeFirst(); + //flist.takeFirst(); + QStack vec; + vec.append(true); + vec.append(false); +} + void testQString() { QString str = "Hello "; @@ -1236,9 +1261,31 @@ public: Foo *f; }; +void testUninitialized() +{ + QString s; + QStringList sl; + QMap mii; + QMap mss; + QHash hii; + QHash hss; + QList li; + QVector vi; + QStack si; + + std::string ss; + std::map smii; + std::map smss; + std::list sli; + std::list ssl; + std::vector svi; + std::stack ssi; +} int main(int argc, char *argv[]) { + testQStack(); + testUninitialized(); testPointer(); testQFileInfo(); testObject1();