forked from qt-creator/qt-creator
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:
@@ -47,6 +47,7 @@
|
||||
#include <QtCore/QPointer>
|
||||
#include <QtCore/QRect>
|
||||
#include <QtCore/QRectF>
|
||||
#include <QtCore/QStack>
|
||||
#include <QtCore/QSize>
|
||||
#include <QtCore/QSizeF>
|
||||
#include <QtCore/QString>
|
||||
@@ -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<const QByteArray *>(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<QHashData *const*>(d.data);
|
||||
qCheckAccess(deref(d.data));
|
||||
const char *keyType = d.templateParameters[0];
|
||||
const char *valueType = d.templateParameters[1];
|
||||
|
||||
QHashData *h = *reinterpret_cast<QHashData *const*>(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<const QImage *>(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<T> has only a single member
|
||||
// of type union { QListData p; QListData::Data *d; };
|
||||
|
||||
const QListData &ldata = *reinterpret_cast<const QListData*>(d.data);
|
||||
const QListData::Data *pdata =
|
||||
*reinterpret_cast<const QListData::Data* const*>(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<T> has only a single member
|
||||
// of type union { QLinkedListData *d; QLinkedListNode<T> *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<QMapData *const*>(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<const QObject *>(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<const QVariant *>(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<const QString *>(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<const QStringList *>(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<const QTextCodec *>(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<int> *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\","
|
||||
|
@@ -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,
|
||||
_("<Breaking endless loop for %1>").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;
|
||||
|
@@ -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;
|
||||
|
@@ -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
|
||||
};
|
||||
|
@@ -36,6 +36,7 @@
|
||||
#include <QtCore/QMap>
|
||||
#include <QtCore/QPointer>
|
||||
#include <QtCore/QString>
|
||||
#include <QtCore/QStack>
|
||||
#include <QtCore/QThread>
|
||||
#include <QtCore/QVariant>
|
||||
#include <QtCore/QVector>
|
||||
@@ -855,6 +856,30 @@ void testQStandardItemModel()
|
||||
+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()
|
||||
{
|
||||
QString str = "Hello ";
|
||||
@@ -1236,9 +1261,31 @@ public:
|
||||
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[])
|
||||
{
|
||||
testQStack();
|
||||
testUninitialized();
|
||||
testPointer();
|
||||
testQFileInfo();
|
||||
testObject1();
|
||||
|
Reference in New Issue
Block a user