debugger: small improvements to dumpers

Add a dumper for QStack. Also don't crash when accessing an uninitialized
pointer when the pointer looks bad to begin with.
This commit is contained in:
hjk
2009-08-28 09:44:11 +02:00
parent b901b5013d
commit 9a5908bf8c
5 changed files with 123 additions and 25 deletions

View File

@@ -47,6 +47,7 @@
#include <QtCore/QPointer> #include <QtCore/QPointer>
#include <QtCore/QRect> #include <QtCore/QRect>
#include <QtCore/QRectF> #include <QtCore/QRectF>
#include <QtCore/QStack>
#include <QtCore/QSize> #include <QtCore/QSize>
#include <QtCore/QSizeF> #include <QtCore/QSizeF>
#include <QtCore/QString> #include <QtCore/QString>
@@ -270,15 +271,45 @@ static bool startsWith(const char *s, const char *t)
return true; 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. // 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 // On Windows, try to be less crash-prone by checking memory using WinAPI
#ifdef Q_OS_WIN #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 #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 #endif
#ifdef QT_NAMESPACE #ifdef QT_NAMESPACE
@@ -848,6 +879,7 @@ static void qDumpUnknown(QDumper &d, const char *why = 0)
why = DUMPUNKNOWN_MESSAGE; why = DUMPUNKNOWN_MESSAGE;
d.putItem("value", why); d.putItem("value", why);
d.putItem("type", d.outertype); d.putItem("type", d.outertype);
d.putItem("valuedisabled", "true");
d.putItem("numchild", "0", d.currentChildNumChild); d.putItem("numchild", "0", d.currentChildNumChild);
d.disarm(); d.disarm();
} }
@@ -1143,6 +1175,7 @@ static void qDumpQAbstractItemModel(QDumper &d)
static void qDumpQByteArray(QDumper &d) static void qDumpQByteArray(QDumper &d)
{ {
qCheckAccess(deref(d.data));
const QByteArray &ba = *reinterpret_cast<const QByteArray *>(d.data); const QByteArray &ba = *reinterpret_cast<const QByteArray *>(d.data);
if (!ba.isEmpty()) { if (!ba.isEmpty()) {
@@ -1408,10 +1441,11 @@ int hashOffset(bool optimizedIntKey, bool forKey, unsigned keySize, unsigned val
static void qDumpQHash(QDumper &d) static void qDumpQHash(QDumper &d)
{ {
QHashData *h = *reinterpret_cast<QHashData *const*>(d.data); qCheckAccess(deref(d.data));
const char *keyType = d.templateParameters[0]; const char *keyType = d.templateParameters[0];
const char *valueType = d.templateParameters[1]; const char *valueType = d.templateParameters[1];
QHashData *h = *reinterpret_cast<QHashData *const*>(d.data);
qCheckPointer(h->fakeNext); qCheckPointer(h->fakeNext);
qCheckPointer(h->buckets); qCheckPointer(h->buckets);
@@ -1515,6 +1549,7 @@ static void qDumpQHashNode(QDumper &d)
#if USE_QT_GUI #if USE_QT_GUI
static void qDumpQImage(QDumper &d) static void qDumpQImage(QDumper &d)
{ {
qCheckAccess(deref(d.data));
const QImage &im = *reinterpret_cast<const QImage *>(d.data); const QImage &im = *reinterpret_cast<const QImage *>(d.data);
d.beginItem("value"); d.beginItem("value");
d.put("(").put(im.width()).put("x").put(im.height()).put(")"); 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) static void qDumpQList(QDumper &d)
{ {
qCheckAccess(deref(d.data));
// This uses the knowledge that QList<T> has only a single member // This uses the knowledge that QList<T> has only a single member
// of type union { QListData p; QListData::Data *d; }; // of type union { QListData p; QListData::Data *d; };
const QListData &ldata = *reinterpret_cast<const QListData*>(d.data); const QListData &ldata = *reinterpret_cast<const QListData*>(d.data);
const QListData::Data *pdata = const QListData::Data *pdata =
*reinterpret_cast<const QListData::Data* const*>(d.data); *reinterpret_cast<const QListData::Data* const*>(d.data);
qCheckAccess(pdata);
int nn = ldata.size(); int nn = ldata.size();
if (nn < 0) if (nn < 0)
return; return;
if (nn > 0) { if (nn > 0) {
qCheckAccess(ldata.d->array);
//qCheckAccess(ldata.d->array[0]);
//qCheckAccess(ldata.d->array[nn - 1]);
if (ldata.d->begin < 0) if (ldata.d->begin < 0)
return; return;
if (ldata.d->begin > ldata.d->end) if (ldata.d->begin > ldata.d->end)
@@ -1578,7 +1610,11 @@ static void qDumpQList(QDumper &d)
if (ldata.d->ref._q_value <= 0) if (ldata.d->ref._q_value <= 0)
return; return;
#endif #endif
qCheckAccess(ldata.d->array);
//qCheckAccess(ldata.d->array[0]);
//qCheckAccess(ldata.d->array[nn - 1]);
} }
qCheckAccess(pdata);
int n = nn; int n = nn;
d.putItemCount("value", n); d.putItemCount("value", n);
@@ -1635,6 +1671,7 @@ static void qDumpQList(QDumper &d)
static void qDumpQLinkedList(QDumper &d) static void qDumpQLinkedList(QDumper &d)
{ {
qCheckAccess(deref(d.data));
// This uses the knowledge that QLinkedList<T> has only a single member // This uses the knowledge that QLinkedList<T> has only a single member
// of type union { QLinkedListData *d; QLinkedListNode<T> *e; }; // of type union { QLinkedListData *d; QLinkedListNode<T> *e; };
const QLinkedListData *ldata = const QLinkedListData *ldata =
@@ -1760,6 +1797,7 @@ static void qDumpQMapNode(QDumper &d)
static void qDumpQMap(QDumper &d) static void qDumpQMap(QDumper &d)
{ {
qCheckAccess(deref(d.data));
QMapData *h = *reinterpret_cast<QMapData *const*>(d.data); QMapData *h = *reinterpret_cast<QMapData *const*>(d.data);
const char *keyType = d.templateParameters[0]; const char *keyType = d.templateParameters[0];
const char *valueType = d.templateParameters[1]; const char *valueType = d.templateParameters[1];
@@ -1898,6 +1936,7 @@ static void qDumpQModelIndex(QDumper &d)
static void qDumpQObject(QDumper &d) static void qDumpQObject(QDumper &d)
{ {
qCheckAccess(deref(d.data));
const QObject *ob = reinterpret_cast<const QObject *>(d.data); const QObject *ob = reinterpret_cast<const QObject *>(d.data);
const QMetaObject *mo = ob->metaObject(); const QMetaObject *mo = ob->metaObject();
d.putItem("value", ob->objectName()); d.putItem("value", ob->objectName());
@@ -2147,6 +2186,7 @@ static void qDumpQVariant(QDumper &d, const QVariant *v)
static inline void qDumpQVariant(QDumper &d) static inline void qDumpQVariant(QDumper &d)
{ {
qCheckAccess(deref(d.data));
qDumpQVariant(d, reinterpret_cast<const QVariant *>(d.data)); qDumpQVariant(d, reinterpret_cast<const QVariant *>(d.data));
} }
@@ -2772,6 +2812,7 @@ static void qDumpQSharedPointer(QDumper &d)
static void qDumpQString(QDumper &d) static void qDumpQString(QDumper &d)
{ {
qCheckAccess(deref(d.data));
const QString &str = *reinterpret_cast<const QString *>(d.data); const QString &str = *reinterpret_cast<const QString *>(d.data);
const int size = str.size(); const int size = str.size();
@@ -2796,6 +2837,7 @@ static void qDumpQString(QDumper &d)
static void qDumpQStringList(QDumper &d) static void qDumpQStringList(QDumper &d)
{ {
qCheckAccess(deref(d.data));
const QStringList &list = *reinterpret_cast<const QStringList *>(d.data); const QStringList &list = *reinterpret_cast<const QStringList *>(d.data);
int n = list.size(); int n = list.size();
if (n < 0) if (n < 0)
@@ -2827,6 +2869,7 @@ static void qDumpQStringList(QDumper &d)
static void qDumpQTextCodec(QDumper &d) static void qDumpQTextCodec(QDumper &d)
{ {
qCheckPointer(deref(d.data));
const QTextCodec &codec = *reinterpret_cast<const QTextCodec *>(d.data); const QTextCodec &codec = *reinterpret_cast<const QTextCodec *>(d.data);
d.putItem("value", codec.name()); d.putItem("value", codec.name());
d.putItem("valueencoded", "1"); d.putItem("valueencoded", "1");
@@ -2843,6 +2886,7 @@ static void qDumpQTextCodec(QDumper &d)
static void qDumpQVector(QDumper &d) static void qDumpQVector(QDumper &d)
{ {
qCheckAccess(deref(d.data));
QVectorTypedData<int> *dummy = 0; QVectorTypedData<int> *dummy = 0;
const unsigned typeddatasize = (char*)(&dummy->array) - (char*)dummy; const unsigned typeddatasize = (char*)(&dummy->array) - (char*)dummy;
@@ -3421,6 +3465,8 @@ static void handleProtocolVersion2and3(QDumper &d)
#ifndef QT_BOOTSTRAPPED #ifndef QT_BOOTSTRAPPED
else if (isEqual(type, "QSet")) else if (isEqual(type, "QSet"))
qDumpQSet(d); qDumpQSet(d);
else if (isEqual(type, "QStack"))
qDumpQVector(d);
#if QT_VERSION >= 0x040500 #if QT_VERSION >= 0x040500
else if (isEqual(type, "QSharedPointer")) else if (isEqual(type, "QSharedPointer"))
qDumpQSharedPointer(d); qDumpQSharedPointer(d);
@@ -3596,6 +3642,7 @@ void *qDumpObjectData440(
"\""NS"QRectF\"," "\""NS"QRectF\","
//"\""NS"QRegion\"," //"\""NS"QRegion\","
"\""NS"QSet\"," "\""NS"QSet\","
"\""NS"QStack\","
"\""NS"QString\"," "\""NS"QString\","
"\""NS"QStringList\"," "\""NS"QStringList\","
"\""NS"QTextCodec\"," "\""NS"QTextCodec\","

View File

@@ -2907,7 +2907,8 @@ void GdbEngine::runDebuggingHelper(const WatchData &data0, bool dumpChildren)
WatchData data = data0; WatchData data = data0;
// Avoid endless loops created by faulty dumpers // 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, emit gdbInputAvailable(LogStatus,
_("<Breaking endless loop for %1>").arg(data.iname)); _("<Breaking endless loop for %1>").arg(data.iname));
data.setAllUnneeded(); data.setAllUnneeded();
@@ -2916,7 +2917,7 @@ void GdbEngine::runDebuggingHelper(const WatchData &data0, bool dumpChildren)
insertData(data); insertData(data);
return; return;
} }
m_processedNames.insert(data.iname); m_processedNames.insert(processedName);
QByteArray params; QByteArray params;
QStringList extraArgs; QStringList extraArgs;
@@ -3427,7 +3428,7 @@ void GdbEngine::handleDebuggingHelperValue2(const GdbResultRecord &record,
WatchData childtemplate; WatchData childtemplate;
setWatchDataType(childtemplate, contents.findChild("childtype")); setWatchDataType(childtemplate, contents.findChild("childtype"));
setWatchDataChildCount(childtemplate, contents.findChild("childnumchild")); setWatchDataChildCount(childtemplate, contents.findChild("childnumchild"));
//qDebug() << "DATA:" << data.toString(); //qDebug() << "CHILD TEMPLATE:" << childtemplate.toString();
qq->watchHandler()->insertData(data); qq->watchHandler()->insertData(data);
int i = 0; int i = 0;

View File

@@ -785,24 +785,26 @@ QtDumperHelper::Type QtDumperHelper::specialType(QString s)
} else { } else {
s = s.mid(namespaceIndex + 2); 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")) if (s == QLatin1String("QAbstractItem"))
return QAbstractItemType; return QAbstractItemType;
if (s == QLatin1String("QMap")) if (s == QLatin1String("QMap"))
return QMapType; return QMapType;
if (s == QLatin1String("QMultiMap"))
return QMultiMapType;
if (s == QLatin1String("QMapNode")) if (s == QLatin1String("QMapNode"))
return QMapNodeType; 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; return UnknownType;
} }
@@ -1458,6 +1460,7 @@ void QtDumperHelper::evaluationParameters(const WatchData &data,
break; break;
case SupportedType: case SupportedType:
case QVectorType: case QVectorType:
case QStackType:
case QObjectType: case QObjectType:
case QWidgetType: case QWidgetType:
break; break;

View File

@@ -160,7 +160,7 @@ public:
// Below types require special handling // Below types require special handling
QAbstractItemType, QAbstractItemType,
QObjectType, QWidgetType, QObjectSlotType, QObjectSignalType, QObjectType, QWidgetType, QObjectSlotType, QObjectSignalType,
QVectorType, QMapType, QMultiMapType, QMapNodeType, QVectorType, QMapType, QMultiMapType, QMapNodeType, QStackType,
StdVectorType, StdDequeType, StdSetType, StdMapType, StdStackType, StdVectorType, StdDequeType, StdSetType, StdMapType, StdStackType,
StdStringType StdStringType
}; };

View File

@@ -36,6 +36,7 @@
#include <QtCore/QMap> #include <QtCore/QMap>
#include <QtCore/QPointer> #include <QtCore/QPointer>
#include <QtCore/QString> #include <QtCore/QString>
#include <QtCore/QStack>
#include <QtCore/QThread> #include <QtCore/QThread>
#include <QtCore/QVariant> #include <QtCore/QVariant>
#include <QtCore/QVector> #include <QtCore/QVector>
@@ -855,6 +856,30 @@ void testQStandardItemModel()
+i; +i;
} }
void testQStack()
{
QVector<int> bigv;
for (int i = 0; i < 10; ++i)
bigv.append(i);
QStack<int> big;
for (int i = 0; i < 10; ++i)
big.append(i);
QStack<Foo *> plist;
plist.append(new Foo(1));
plist.append(0);
plist.append(new Foo(2));
QStack<Foo> flist;
flist.append(1);
flist.append(2);
flist.append(3);
flist.append(4);
//flist.takeFirst();
//flist.takeFirst();
QStack<bool> vec;
vec.append(true);
vec.append(false);
}
void testQString() void testQString()
{ {
QString str = "Hello "; QString str = "Hello ";
@@ -1236,9 +1261,31 @@ public:
Foo *f; Foo *f;
}; };
void testUninitialized()
{
QString s;
QStringList sl;
QMap<int, int> mii;
QMap<QString, QString> mss;
QHash<int, int> hii;
QHash<QString, QString> hss;
QList<int> li;
QVector<int> vi;
QStack<int> si;
std::string ss;
std::map<int, int> smii;
std::map<std::string, std::string> smss;
std::list<int> sli;
std::list<std::string> ssl;
std::vector<int> svi;
std::stack<int> ssi;
}
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
testQStack();
testUninitialized();
testPointer(); testPointer();
testQFileInfo(); testQFileInfo();
testObject1(); testObject1();