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/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\","
|
||||||
|
@@ -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;
|
||||||
|
@@ -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;
|
||||||
|
@@ -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
|
||||||
};
|
};
|
||||||
|
@@ -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();
|
||||||
|
Reference in New Issue
Block a user