From 1fad39c9234839617470b3ff626d4e3f1311da1a Mon Sep 17 00:00:00 2001
From: Friedemann Kleint <Friedemann.Kleint@nokia.com>
Date: Fri, 2 Oct 2009 15:17:50 +0200
Subject: [PATCH] CDB: Fix dumper regression

- Do not deref d-ptr when checking on QVariants of PODS
- Make type/value fixing of dumper results more fine-grained
- Allow children in expandPtrToDumpage (QWidget-Pointers)
- Fix broken size cache (queuePrefix was empty)
- Compile
---
 share/qtcreator/gdbmacros/gdbmacros.cpp       | 28 ++++++++-------
 share/qtcreator/gdbmacros/test/main.cpp       | 12 ++++++-
 .../debugger/cdb/cdbstackframecontext.cpp     | 35 ++++++++++++-------
 .../debugger/cdb/cdbstacktracecontext.cpp     |  3 +-
 src/plugins/debugger/watchutils.cpp           |  3 +-
 5 files changed, 53 insertions(+), 28 deletions(-)

diff --git a/share/qtcreator/gdbmacros/gdbmacros.cpp b/share/qtcreator/gdbmacros/gdbmacros.cpp
index 59049f2673a..072a41c6b14 100644
--- a/share/qtcreator/gdbmacros/gdbmacros.cpp
+++ b/share/qtcreator/gdbmacros/gdbmacros.cpp
@@ -1177,7 +1177,7 @@ static void qDumpQAbstractItemModel(QDumper &d)
 
 static void qDumpQByteArray(QDumper &d)
 {
-    qCheckAccess(deref(d.data));
+    qCheckAccess(deref(d.data)); // is the d-ptr de-referenceable and valid
     const QByteArray &ba = *reinterpret_cast<const QByteArray *>(d.data);
 
     if (!ba.isEmpty()) {
@@ -1461,7 +1461,7 @@ int hashOffset(bool optimizedIntKey, bool forKey, unsigned keySize, unsigned val
 
 static void qDumpQHash(QDumper &d)
 {
-    qCheckAccess(deref(d.data));
+    qCheckAccess(deref(d.data)); // is the d-ptr de-referenceable and valid
     const char *keyType   = d.templateParameters[0];
     const char *valueType = d.templateParameters[1];
 
@@ -1569,7 +1569,7 @@ static void qDumpQHashNode(QDumper &d)
 #if USE_QT_GUI
 static void qDumpQImage(QDumper &d)
 {
-    qCheckAccess(deref(d.data));
+    qCheckAccess(deref(d.data)); // is the d-ptr de-referenceable and valid
     const QImage &im = *reinterpret_cast<const QImage *>(d.data);
     d.beginItem("value");
         d.put("(").put(im.width()).put("x").put(im.height()).put(")");
@@ -1611,7 +1611,7 @@ static void qDumpQImageData(QDumper &d)
 
 static void qDumpQList(QDumper &d)
 {
-    qCheckAccess(deref(d.data));
+    qCheckAccess(deref(d.data)); // is the d-ptr de-referenceable and valid
     // This uses the knowledge that QList<T> has only a single member
     // of type  union { QListData p; QListData::Data *d; };
 
@@ -1691,7 +1691,7 @@ static void qDumpQList(QDumper &d)
 
 static void qDumpQLinkedList(QDumper &d)
 {
-    qCheckAccess(deref(d.data));
+    qCheckAccess(deref(d.data)); // is the d-ptr de-referenceable and valid
     // This uses the knowledge that QLinkedList<T> has only a single member
     // of type  union { QLinkedListData *d; QLinkedListNode<T> *e; };
     const QLinkedListData *ldata =
@@ -1817,7 +1817,7 @@ static void qDumpQMapNode(QDumper &d)
 
 static void qDumpQMap(QDumper &d)
 {
-    qCheckAccess(deref(d.data));
+    qCheckAccess(deref(d.data)); // is the d-ptr de-referenceable and valid
     QMapData *h = *reinterpret_cast<QMapData *const*>(d.data);
     const char *keyType   = d.templateParameters[0];
     const char *valueType = d.templateParameters[1];
@@ -1956,7 +1956,7 @@ static void qDumpQModelIndex(QDumper &d)
 
 static void qDumpQObject(QDumper &d)
 {
-    qCheckAccess(deref(d.data));
+    qCheckAccess(deref(d.data)); // is the d-ptr de-referenceable and valid
     const QObject *ob = reinterpret_cast<const QObject *>(d.data);
     const QMetaObject *mo = ob->metaObject();
     d.putItem("value", ob->objectName());
@@ -2206,7 +2206,7 @@ static void qDumpQVariant(QDumper &d, const QVariant *v)
 
 static inline void qDumpQVariant(QDumper &d)
 {
-    qCheckAccess(deref(d.data));
+    qCheckAccess(d.data);
     qDumpQVariant(d, reinterpret_cast<const QVariant *>(d.data));
 }
 
@@ -2832,7 +2832,7 @@ static void qDumpQSharedPointer(QDumper &d)
 
 static void qDumpQString(QDumper &d)
 {
-    //qCheckAccess(deref(d.data));
+    //qCheckAccess(deref(d.data)); // is the d-ptr de-referenceable and valid
     const QString &str = *reinterpret_cast<const QString *>(d.data);
 
     const int size = str.size();
@@ -2857,7 +2857,7 @@ static void qDumpQString(QDumper &d)
 
 static void qDumpQStringList(QDumper &d)
 {
-    qCheckAccess(deref(d.data));
+    qCheckAccess(deref(d.data)); // is the d-ptr de-referenceable and valid
     const QStringList &list = *reinterpret_cast<const QStringList *>(d.data);
     int n = list.size();
     if (n < 0)
@@ -2906,7 +2906,7 @@ static void qDumpQTextCodec(QDumper &d)
 
 static void qDumpQVector(QDumper &d)
 {
-    qCheckAccess(deref(d.data));
+    qCheckAccess(deref(d.data)); // is the d-ptr de-referenceable and valid
     QVectorTypedData<int> *dummy = 0;
     const unsigned typeddatasize = (char*)(&dummy->array) - (char*)dummy;
 
@@ -3810,7 +3810,11 @@ void *qDumpObjectData440(
         d.exp       = inbuffer; while (*inbuffer) ++inbuffer; ++inbuffer;
         d.innerType = inbuffer; while (*inbuffer) ++inbuffer; ++inbuffer;
         d.iname     = inbuffer; while (*inbuffer) ++inbuffer; ++inbuffer;
-
+#if 0
+        qDebug() << "data=" << d.data << "dumpChildren=" << d.dumpChildren
+                << " extra=" << d.extraInt[0] << d.extraInt[1]  << d.extraInt[2]  << d.extraInt[3]
+                << d.outerType << d.iname << d.exp << d.iname;
+#endif
         handleProtocolVersion2and3(d);
     }
 
diff --git a/share/qtcreator/gdbmacros/test/main.cpp b/share/qtcreator/gdbmacros/test/main.cpp
index b6be579ab38..28dea56f762 100644
--- a/share/qtcreator/gdbmacros/test/main.cpp
+++ b/share/qtcreator/gdbmacros/test/main.cpp
@@ -227,7 +227,17 @@ static int dumpQMapQStringString()
 
 static int dumpQVariant()
 {
-    QVariant test(QLatin1String("item"));
+    QVariant test = QLatin1String("item");
+    prepareInBuffer("QVariant", "local.qvariant", "local.qvariant", "");
+    qDumpObjectData440(2, 42, testAddress(&test), 1, 0, 0,0 ,0);
+    fputs(qDumpOutBuffer, stdout);
+    fputs("\n\n", stdout);
+    test = QVariant(int(42));
+    prepareInBuffer("QVariant", "local.qvariant", "local.qvariant", "");
+    qDumpObjectData440(2, 42, testAddress(&test), 1, 0, 0,0 ,0);
+    fputs(qDumpOutBuffer, stdout);
+    fputs("\n\n", stdout);
+    test = QVariant(double(3.141));
     prepareInBuffer("QVariant", "local.qvariant", "local.qvariant", "");
     qDumpObjectData440(2, 42, testAddress(&test), 1, 0, 0,0 ,0);
     fputs(qDumpOutBuffer, stdout);
diff --git a/src/plugins/debugger/cdb/cdbstackframecontext.cpp b/src/plugins/debugger/cdb/cdbstackframecontext.cpp
index 76d5e00cf88..93ab11d75ef 100644
--- a/src/plugins/debugger/cdb/cdbstackframecontext.cpp
+++ b/src/plugins/debugger/cdb/cdbstackframecontext.cpp
@@ -128,21 +128,29 @@ WatchHandleDumperInserter::WatchHandleDumperInserter(WatchHandler *wh,
     Q_ASSERT(m_hexNullPattern.isValid());
 }
 
-
 // Prevent recursion of the model by setting value and type
-static inline void fixDumperValueAndType(WatchData *wd, const WatchData *source = 0)
-{
-    static const QString unknown = QCoreApplication::translate("CdbStackFrameContext", "<Unknown>");
-    if (wd->isTypeNeeded() || wd->type.isEmpty()) {
-        wd->setType(source ? source->type : unknown);
+static inline bool fixDumperType(WatchData *wd, const WatchData *source = 0)
+{    
+    const bool missing = wd->isTypeNeeded() || wd->type.isEmpty();
+    if (missing) {
+        static const QString unknownType = QCoreApplication::translate("CdbStackFrameContext", "<Unknown Type>");
+        wd->setType(source ? source->type : unknownType);
     }
-    if (wd->isValueNeeded()) {
+    return missing;
+}
+
+static inline bool fixDumperValue(WatchData *wd, const WatchData *source = 0)
+{
+    const bool missing = wd->isValueNeeded();
+    if (missing) {
         if (source && source->isValueKnown()) {
             wd->setValue(source->value);
         } else {
-            wd->setValue(unknown);
+            static const QString unknownValue = QCoreApplication::translate("CdbStackFrameContext", "<Unknown Value>");
+            wd->setValue(unknownValue);
         }
     }
+    return missing;
 }
 
 // When querying an item, the queried item is sometimes returned in incomplete form.
@@ -160,7 +168,8 @@ static inline void fixDumperResult(const WatchData &source,
     WatchData &returned = result->front();
     if (returned.iname != source.iname)
         return;
-    fixDumperValueAndType(&returned, &source);
+    fixDumperType(&returned, &source);
+    fixDumperValue(&returned, &source);
     // Indicate owner and known children
     returned.source = OwnerDumper;
     if (returned.isChildrenKnown() && returned.isHasChildrenKnown() && returned.hasChildren)
@@ -179,7 +188,9 @@ static inline void fixDumperResult(const WatchData &source,
         it->source = OwnerDumper;
         if (it->isChildrenKnown() && it->isHasChildrenKnown() && it->hasChildren)
             it->source |= CdbStackFrameContext::ChildrenKnownBit;
-        if (wd.addr.isEmpty() && wd.isSomethingNeeded()) {
+        // Cannot dump items with missing addresses or missing types
+        const bool typeFixed = fixDumperType(&wd); // Order of evaluation!
+        if ((wd.addr.isEmpty() && wd.isSomethingNeeded()) || typeFixed) {
             wd.setHasChildren(false);
             wd.setAllUnneeded();
         } else {
@@ -188,8 +199,6 @@ static inline void fixDumperResult(const WatchData &source,
             if (suppressGrandChildren && (wd.isChildrenNeeded() || wd.isHasChildrenNeeded()))
                 wd.setHasChildren(false);
         }
-        //   <Out of scope value> have sometimes missing types. Kill recursion
-        fixDumperValueAndType(&wd);
     }
     if (debugCDBWatchHandling)
         debugWatchDataList(*result, "<fixDumperResult");
@@ -226,7 +235,7 @@ bool WatchHandleDumperInserter::expandPointerToDumpable(const WatchData &wd, QSt
         const CdbDumperHelper::DumpResult dr = m_dumper->dumpType(derefedWd, true, &m_dumperResult, errorMessage);
         if (dr != CdbDumperHelper::DumpOk)
             break;
-        fixDumperResult(derefedWd, &m_dumperResult, true);
+        fixDumperResult(derefedWd, &m_dumperResult, false);
         // Insert the pointer item with 1 additional child + its dumper results
         // Note: formal arguments might already be expanded in the symbol group.
         WatchData ptrWd = wd;
diff --git a/src/plugins/debugger/cdb/cdbstacktracecontext.cpp b/src/plugins/debugger/cdb/cdbstacktracecontext.cpp
index 6cdaf627092..40cd9776bcb 100644
--- a/src/plugins/debugger/cdb/cdbstacktracecontext.cpp
+++ b/src/plugins/debugger/cdb/cdbstacktracecontext.cpp
@@ -86,7 +86,8 @@ bool CdbStackTraceContext::init(unsigned long frameCount, QString * /*errorMessa
     // Convert the DEBUG_STACK_FRAMEs to our StackFrame structure and populate the frames
     WCHAR wszBuf[MAX_PATH];
     for (ULONG i=0; i < frameCount; ++i) {
-        StackFrame frame(i);
+        StackFrame frame;
+        frame.level = i;
         const ULONG64 instructionOffset = m_cdbFrames[i].InstructionOffset;
         if (i == 0)
             m_instructionOffset = instructionOffset;
diff --git a/src/plugins/debugger/watchutils.cpp b/src/plugins/debugger/watchutils.cpp
index 8208cb4fcf1..a494c0d7000 100644
--- a/src/plugins/debugger/watchutils.cpp
+++ b/src/plugins/debugger/watchutils.cpp
@@ -560,7 +560,7 @@ QString QtDumperHelper::toString(bool debug) const
         str << "\nSize cache: ";
         const SizeCache::const_iterator scend = m_sizeCache.constEnd();
         for (SizeCache::const_iterator it = m_sizeCache.constBegin(); it != scend; ++it) {
-            str << ' ' << it.key() << '=' << it.value();
+            str << ' ' << it.key() << '=' << it.value() << '\n';
         }
         str << "\nExpression cache: (" << m_expressionCache.size() << ")\n";
         const QMap<QString, QString>::const_iterator excend = m_expressionCache.constEnd();
@@ -888,6 +888,7 @@ void QtDumperHelper::setQClassPrefixes(const QString &qNamespace)
     m_qListPrefix = qClassName(qNamespace, "QList");
     m_qLinkedListPrefix = qClassName(qNamespace, "QLinkedList");
     m_qVectorPrefix = qClassName(qNamespace, "QVector");
+    m_qQueuePrefix = qClassName(qNamespace, "QQueue");
 }
 
 static inline double getDumperVersion(const GdbMi &contents)
-- 
GitLab