I'm using QAbstractListModel to expose data to QML ListView. QML SectionScroller is used beside this, which uses get and data functions.
After some time of scrolling, a crash is experienced. The backtrace is:
Program received signal SIGILL, Illegal instruction.
0x0000cdcc in QBasicAtomicInt::ref (
this=0x35)
at /usr/include/QtCore/qatomic_armv6.h:119
119 /usr/include/QtCore/qatomic_armv6.h: No such file or directory.
in /usr/include/QtCore/qatomic_armv6.h
(gdb) bt
#0 0x0000cdcc in QBasicAtomicInt::ref (
this=0x35)
at /usr/include/QtCore/qatomic_armv6.h:119
#1 0x0000f4e8 in QString (
this=0xbebf1a5c, other=...)
at /usr/include/QtCore/qstring.h:729
#2 [address] in IrregularVerb::getForm0
(this=0x92e428) at IrregularVerb.h:16
#3 0x0000e29c in IrregularListWrapper::data (this=0x92dd20, index=..., role=33)
at IrregularListWrapper.cpp:37
#4 0x4010e9c6 in ?? ()
from /usr/lib/libQtDeclarative.so.4
#5 0x4010e9c6 in ?? ()
from /usr/lib/libQtDeclarative.so.4
Backtrace stopped: previous frame identical to this frame (corrupt stack?)
On other device (first is N900, the second N950) the backtrace is similar. It's SIGSEGV instead of SIGILL, but the backtrace is identical beside this. I noticed once a situtation where some of the fields have gotten blank at the moment on crash. (the ones using getForm0 and getForm1)
When I added an extra assignement, to the returned value, the crash happened at the assignment.
Some important code:
The element:
class IrregularVerb : public QObject
{
Q_OBJECT
Q_PROPERTY(QString form0 READ getForm0 CONSTANT)
Q_PROPERTY(QString form1 READ getForm1 CONSTANT)
Q_PROPERTY(QString form2 READ getForm2 CONSTANT)
public:
QString forms[3];
QString getForm0() const { return forms[0]; }
QString getForm1() const { return forms[1]; }
QString getForm2() const { return forms[2]; }
IrregularVerb(QString a, QString b, QString c) { forms[0] = a; forms[1] = b; forms[2] = c; }
};
The model:
class IrregularListWrapper : public QAbstractListModel
{
Q_OBJECT
Q_PROPERTY(QString langName READ getLangName NOTIFY langChanged)
Q_PROPERTY(int count READ rowCount NOTIFY langChanged)
Q_ENUMS(Language)
public:
Q_INVOKABLE int rowCount(const QModelIndex& = QModelIndex()) const { return db->count(); }
Q_INVOKABLE QObject* get(int index) const {return db->at(index);}
QVariant data(const QModelIndex &index, int role) const;
enum Language
{
English = 0,
German = 1
};
enum IrregularVerbRoles
{
Form0Role = Qt::UserRole + 1,
Form1Role,
Form2Role
};
IrregularListWrapper();
QString getLangName() const { return langName; }
Q_INVOKABLE void changeLang(Language l) { beginResetModel(); db = 0; setLang(l); endResetModel(); }
static QMap<Language, QString> plugins;
signals:
void langChanged();
protected:
void setLang(Language);
QString langName;
AbstractIrregularList * db;
};
QVariant IrregularListWrapper::data(const QModelIndex &index, int role) const
{
if (!index.isValid()) return QVariant();
int rowno = index.row();
qDebug() << "Row is " << index.row() << flush;
const IrregularVerb* verb = db->at(index.row());
switch (role)
{
case Form0Role:
return verb->getForm0();
break;
case Form1Role:
return verb->getForm1();
break;
case Form2Role:
return verb->getForm2();
break;
}
return QVariant();
}
AbstractIrregularList:
class AbstractIrregularList : public QObject, public QList<IrregularVerb*>
{
Q_OBJECT
public:
void IV(const char* a, const char* b, const char* c) { append (new IrregularVerb(a, b, c)); }
void IV(const char *a, const char *b) { IV(a, b, b); }
void IV(const char *a) { IV(a,a,a); }
};
Q_DECLARE_INTERFACE(AbstractIrregularList, "com.marmistrz.Plugin.AbstractIrregularList/1.0");
Do you have an idea why it's happening? Thanks!
/edit1: Thanks for your reply. Would this be ok?
Q_INVOKABLE QObject* get(int index)
{
QObject* item = db->at(index);
QDeclarativeEngine::setObjectOwnership(item, QDeclarativeEngine::CppOwnership);
item->setParent(this); // do I need to do this? An QList<QObject*>-child would clean it, right?
return item;
}
Thanks
It looks like you have a "classic" problem using
QAbstractListModel
on QML side. YourIrregularListWrapper
hasget
method which returns objects with JS ownership (that kind of ownership is default forQ_INVOKABLE
methods) and they will be garbage collected with JS engine on QML side. To prevent this you should change objects' ownership before returning them to QML withQDeclarativeEngine::setObjectOwnership
. See example in my answer here.