在QML中访问野指针属性导致程序崩溃

1.情况

最近在对之前写的一个软件进行重构,重构完之后,给到现场去用。
现场反馈说,软件操作操作着,就崩溃了。
由于软件在崩溃时会保留dump文件的(实现过程看这里:【Qt下生成pdb文件,并在exe崩溃时生成dmp文件,且由dmp查询崩溃原因】),通过dump文件,能够得到的信息为:
在这里插入图片描述

>	Qt5Core.dll!QtSharedPointer::ExternalRefCountData::getAndRef(const QObject * obj=0x0000020c9821aa70)1398	C++	已加载符号。
 	[内联框架] Qt5Qml.dll!QV4::QQmlQPointer<QObject>::init(QObject *)223	C++	已加载符号。
 	[内联框架] Qt5Qml.dll!QV4::Heap::QObjectWrapper::init(QObject *)83	C++	已加载符号。
 	[内联框架] Qt5Qml.dll!QV4::MemoryManager::allocate(QObject *)245	C++	已加载符号。
 	Qt5Qml.dll!QV4::QObjectWrapper::create(QV4::ExecutionEngine * engine=0x0000020be3868650, QObject * object=0x0000020c9821aa70)694	C++	已加载符号。
 	Qt5Qml.dll!QV4::QObjectWrapper::wrap_slowPath(QV4::ExecutionEngine * engine=0x0000020be3868650, QObject * object=0x0000020c9821aa70)599	C++	已加载符号。
 	[内联框架] Qt5Qml.dll!QV4::QObjectWrapper::wrap(QV4::ExecutionEngine * object=0x0000020c9821aa70, QObject *)222	C++	已加载符号。
 	Qt5Qml.dll!loadProperty(QV4::ExecutionEngine * v4=0x0000020be3868650, QObject * object=0x0000020be86135b0, const QQmlPropertyData & property)139	C++	已加载符号。
 	Qt5Qml.dll!QV4::QObjectWrapper::lookupGetterImpl<unsigned __int64 <lambda>(void)>(QV4::Lookup * lookup=0x0000020be4d81c20, QV4::ExecutionEngine * engine=0x0000020be3868650, const QV4::Value & object, bool useOriginalProperty, QV4::QObjectWrapper::lookupGetter::__l2::unsigned __int64 <lambda>(void) revertLookup=unsigned __int64 <lambda>(void){...})262	C++	已加载符号。
 	Qt5Qml.dll!QV4::QObjectWrapper::lookupGetter(QV4::Lookup * lookup, QV4::ExecutionEngine * engine, const QV4::Value & object)896	C++	已加载符号。
 	0000020c02a00b3f()	未知	未加载任何符号。

这些全是qml里面的东西,又不给从c++到qml的调用堆栈,哪怕只是qml代码的调用堆栈也好。不知道怎么定位好了。

2.debug

然后我就开始漫长的debug了。
首先,按照现场人员的操作步骤,我在我的电脑上也复现了这个崩溃。那就说明这个应该是和设备无关的。
然后我在QtCreator上打开工程,进入debug模式,然后按照指定的步骤操作,也得到了类似的堆栈信息:
在这里插入图片描述
虽然信息长了一些,但是还是没有qml代码的调用堆栈。但是,看看灰色那里
在这里插入图片描述QQuickAbstractButton::clicked,那就是在点击某个Button之后触发的这个错误,而在操作的最后一步,的确是按了某个按钮。
然后我就把这个按钮的onclicked槽函数屏蔽掉,然后再测试就没问题了。那就说明是这个槽函数里面的某行代码出问题了。
接着,我就一部分一部分、一行一行代码地注释/取消注释地测试,最后定位到了那一行。
定位到那一行后,后面又针对这行代码反复测试、联系前后文上下文来猜想,然后对这行代码研究了一两天后,发现在某些情况下,代码中访问的某个item的属性可能为野指针。
然后单独写了个测试程序来测试,好家伙,报错的堆栈结构一模一样,那就确定是这个野指针的问题了。

3.测试程序

这里我简单介绍一下我后面用的测试程序,方便大家复现。
在qml工程中,添加两个c++类:JobItemToolItem。其中JobItem有个属性curItem,其类型为ToolItem *。如下图所示
在这里插入图片描述
然后在JobItem 的构造函数中,对属性curItem赋值
在这里插入图片描述接着把这两个类注册到qml中

    qmlRegisterType<JobItem>("ZyCppItems", 1, 0, "JobItem");
    qmlRegisterType<ToolItem>("ZyCppItems", 1, 0, "ToolItem");

然后在qml中创建,并测试:
在这里插入图片描述点击按钮,就得到了前面的报错了。

4.解决方案

使用QPointer。
不改变属性的类型,但是稍微改变一下该属性在C++这边的的存储形式:
在这里插入图片描述在这里插入图片描述这样一来,因为QPointer会通过一定的机制(详情请查看这里:【Qt之QPointer】)根据对象是否被析构而动态改变自己的值,我们就不用担心会访问到野指针了。在指针被delete后,qml访问到的属性自动变成null了:
在这里插入图片描述


参考:
【Qt之QPointer】

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值