问题描述
QSettingBackend 的析构函数为空实现,且 QSettings 以 backend 为 parent:
backend 被销毁(尤其从主线程跨线程销毁)时会连带销毁 QSettings,与写线程在途的
doSetOption 存在 use-after-free 竞态;同时 writeLock 可能在锁定状态下被
析构(Qt 报 QMutex: destroying locked mutex,属未定义行为)。
机制(dtkcore 6.7.44)
DSettings::setBackend() 将 backend moveToThread 到专门的写线程,
doSetOption/doSync 经队列在该线程异步执行;
- 写线程生命周期仅由
DSettings::destroyed 信号管理(quit()+wait());
~QSettingBackend() 为空——无锁保护、无线程同步:
QSettingBackend::~QSettingBackend() { } // 空析构
void QSettingBackend::doSetOption(...) {
d->writeLock.lock();
d->settings->setValue(...); // 写线程访问 QSettings
...
d->writeLock.unlock();
}
现场证据(deepin-editor CI UT,SIGSEGV exit 139)
使用方(deepin-editor)在 ~Settings() 中先 delete backend(未先析构
DSettings),core 堆栈显示崩溃发生在 DTK 写线程:
#0 QSettings::setValue(...) ← UAF
#1 Dtk::Core::QSettingBackend::doSetOption(...)
#2 QObject::event(QEvent*) ← 队列事件派发
#12 QThread::exec() ← 写线程事件循环
析构期间日志同时出现 QMutex: destroying locked mutex,与 UAF 为同一竞态的两个表现。
全量测试套件下必现;单用例不触发(竞态依赖在途写事件)。
建议(任选其一或组合)
~QSettingBackend() 内先 d->writeLock.lock(),锁内清理 settings
(QSettings 改为手动管理,不挂 parent 自动销毁),确保与在途写操作互斥;
- 或将写线程生命周期收归
QSettingBackend 自身管理(析构时 quit+wait),
不依赖 DSettings::destroyed;
- 至少在文档中明确销毁顺序契约:backend 必须晚于所属 DSettings 析构。
注:deepin-editor 侧已按"先析构 DSettings 再删除 backend"规避
(linuxdeepin/deepin-editor#629),但库层面的跨线程销毁风险仍在。
问题描述
QSettingBackend的析构函数为空实现,且QSettings以 backend 为 parent:backend 被销毁(尤其从主线程跨线程销毁)时会连带销毁 QSettings,与写线程在途的
doSetOption存在 use-after-free 竞态;同时writeLock可能在锁定状态下被析构(Qt 报
QMutex: destroying locked mutex,属未定义行为)。机制(dtkcore 6.7.44)
DSettings::setBackend()将 backendmoveToThread到专门的写线程,doSetOption/doSync经队列在该线程异步执行;DSettings::destroyed信号管理(quit()+wait());~QSettingBackend()为空——无锁保护、无线程同步:现场证据(deepin-editor CI UT,SIGSEGV exit 139)
使用方(deepin-editor)在
~Settings()中先delete backend(未先析构DSettings),core 堆栈显示崩溃发生在 DTK 写线程:
析构期间日志同时出现
QMutex: destroying locked mutex,与 UAF 为同一竞态的两个表现。全量测试套件下必现;单用例不触发(竞态依赖在途写事件)。
建议(任选其一或组合)
~QSettingBackend()内先d->writeLock.lock(),锁内清理settings(QSettings 改为手动管理,不挂 parent 自动销毁),确保与在途写操作互斥;
QSettingBackend自身管理(析构时 quit+wait),不依赖
DSettings::destroyed;注:deepin-editor 侧已按"先析构 DSettings 再删除 backend"规避
(linuxdeepin/deepin-editor#629),但库层面的跨线程销毁风险仍在。