I have a QtQuick app where the user can select a node in QuickQanava and hit a keystroke to delete it from the view. When that happens, I directly call qan::Graph::removeNode()
and my app crashes with the following message:
ASSERT failure in qan::Node: "Called object is not of the correct type (class destructor may have already run)", file /usr/include/qt6/QtCore/qobjectdefs_impl.h, line 119 (/usr/include/qt6/QtCore/qobjectdefs_impl.h:119, unknown function)
Further analysis reveals that the problem comes from somewhere deep inside QuickQanava (or possibly even Qt). See the following backtrace:
#0 0x00007ffff50a164c in () at /usr/lib/libc.so.6
#1 0x00007ffff5051958 in raise () at /usr/lib/libc.so.6
#2 0x00007ffff503b53d in abort () at /usr/lib/libc.so.6
#3 0x00007ffff56a41c7 in () at /usr/lib/libQt6Core.so.6
#4 0x00007ffff56a449a in qt_assert(char const*, char const*, int) () at /usr/lib/libQt6Core.so.6
#5 0x00007ffff56a4559 in () at /usr/lib/libQt6Core.so.6
#6 0x00005555556808a8 in QtPrivate::assertObjectType<qan::Node>(QObject*) (o=0x555555cce170) at /usr/include/qt6/QtCore/qobjectdefs_impl.h:119
#7 0x00005555556803df in QtPrivate::FunctorCall<QtPrivate::IndexesList<>, QtPrivate::List<>, void, void (qan::Node::*)()>::call(void (qan::Node::*)(), qan::Node*, void**)
(f=(void (qan::Node::*)(qan::Node * const)) 0x55555561343e <qan::Node::inDegreeChanged()>, o=0x555555cce170, arg=0x7fffffff9fe8) at /usr/include/qt6/QtCore/qobjectdefs_impl.h:134
#8 0x000055555567ffa4 in QtPrivate::FunctionPointer<void (qan::Node::*)()>::call<QtPrivate::List<>, void>(void (qan::Node::*)(), qan::Node*, void**)
(f=(void (qan::Node::*)(qan::Node * const)) 0x55555561343e <qan::Node::inDegreeChanged()>, o=0x555555cce170, arg=0x7fffffff9fe8) at /usr/include/qt6/QtCore/qobjectdefs_impl.h:172
#9 0x000055555567fc31 in QtPrivate::QSlotObject<void (qan::Node::*)(), QtPrivate::List<>, void>::impl(int, QtPrivate::QSlotObjectBase*, QObject*, void**, bool*) (which=1, this_=0x555555cdae80, r=0x555555cce170, a=0x7fffffff9fe8, ret=0x0)
at /usr/include/qt6/QtCore/qobjectdefs_impl.h:383
#10 0x00007ffff57805c3 in () at /usr/lib/libQt6Core.so.6
#11 0x000055555569c241 in qcm::ContainerModel::lengthChanged() (this=0x555555cad3e0) at /path/redacted/build/lib/quickqanava/QuickContainers/QuickContainers_autogen/6YEA5652QU/moc_qcmContainerModel.cpp:256
#12 0x00005555555afeb8 in qcm::ContainerModel::emitLengthChanged() (this=0x555555cad3e0) at /path/redacted/lib/quickqanava/QuickContainers/include/qcmContainerModel.h:244
#13 0x00005555555afe48 in qcm::ContainerModel::fwdEmitLengthChanged() (this=0x555555cad3e0) at /path/redacted/lib/quickqanava/QuickContainers/include/qcmContainerModel.h:225
#14 0x00005555555b00ae in qcm::AbstractContainer::fwdEmitLengthChanged() (this=0x555555cce230) at /path/redacted/lib/quickqanava/QuickContainers/include/qcmAbstractContainer.h:68
#15 0x000055555564f71a in qcm::Container<QList, qan::Node*>::clear() (this=0x555555cce230) at /path/redacted/lib/quickqanava/src/../QuickContainers/include/qcmContainer.h:385
#16 0x000055555567f200 in gtpo::node<QObject, qan::Graph, qan::Node, qan::Edge, qan::Group>::~node() (this=0x555555cce170, __in_chrg=<optimized out>) at /path/redacted/lib/quickqanava/src/././gtpo/node.h:79
#17 0x000055555567e812 in qan::Node::~Node() (this=0x555555cce170, __in_chrg=<optimized out>) at /path/redacted/lib/quickqanava/src/qanNode.cpp:69
#18 0x00005555555ae84a in ActorNode::~ActorNode() (this=0x555555cce170, __in_chrg=<optimized out>) at /path/redacted/build/ngui/app_autogen/ZNMSKYHDQK/../../../../ngui/session/actornode.h:15
#19 0x00005555555ae866 in ActorNode::~ActorNode() (this=0x555555cce170, __in_chrg=<optimized out>) at /path/redacted/build/ngui/app_autogen/ZNMSKYHDQK/../../../../ngui/session/actornode.h:15
#20 0x0000555555651072 in gtpo::graph<QQuickItem, qan::Node, qan::Group, qan::Edge>::remove_node(qan::Node*) (this=0x555555b155c0, node=0x555555cce170) at /path/redacted/lib/quickqanava/src/././gtpo/./graph.hpp:177
#21 0x00005555556449e3 in qan::Graph::removeNode(qan::Node*) (this=0x555555b155c0, node=0x555555cce170) at /path/redacted/lib/quickqanava/src/qanGraph.cpp:679
This looks like some type of nasty double-free bug. Curiously, though, this only happens under Linux. When I attempted to reproduce it under macOS, there was the app behaved as expected and did not crash. Unfortunately, my app currently does not compile under Windows, so I cannot verify there.
If it helps, please note that I do not perform any direct calls to the delete
operator, or do not call deleteLater
on anything related to QuickQanava -- in this regard my implementation pretty much follows the example projects. The destructor of my ActorNode
class is implemented as:
virtual ~ActorNode() = default;
bug