Files
VX5_KRO_GearPump/doc/TestPrintWidget_Crash_Risk_Analysis.md
2026-06-30 08:21:08 +08:00

6.6 KiB
Raw Permalink Blame History

TestPrintWidget 崩溃风险分析报告

🔴 高风险(必定崩溃)

1. saveFile() — m_printSetting 空指针解引用

文件: testprintwidget.cpp:435

PrintSettingModel::saveToXml(m_printSetting->model(), writer);

m_printSetting 在 setPrintSettingWidget() 调用前为 nullptr。如果用户在 setPrintSettingWidget() 被调用之前就触发了保存,程序会崩溃。虽然 InkJetPrinter.cpp:104 在构造时调用了它,但如果构造顺序出现问题或 m_PrintSetting 尚未初始化,就会崩溃。

2. saveFile() — qgraphicsitem_cast 返回 null 后解引用

文件: testprintwidget.cpp:406

PicTextItem *picText = qgraphicsitem_cast<PicTextItem*>(item);
writer.writeTextElement(..., QString::fromLocal8Bit("%1").arg(picText->pos().x()));

qgraphicsitem_cast 可能返回 null(当 item 不是 PicTextItem 类型时),紧接着调用 picText->pos().x() 就会崩溃。

3. onFileOpen() — sysPara->devOp 空指针解引用

文件: testprintwidget.cpp:477

sysPara->devOp->fpgaWr(0xa4b0, (unsigned char *)&SpecialVarEnable, 1);
  • sysPara 可能为 null(bindSysPara() 未被调用时)
  • sysPara->devOp 也可能为 null

4. on_newfileButton_pressed() — m_printSetting 空指针解引用

文件: testprintwidget.cpp:1122

m_printSetting->setModel(defModel);

同样的问题,m_printSetting 可能为 null。

5. getShowSelectItemText() — dynamic_cast 后无空检查

文件: testprintwidget.cpp:312-317

PicTextItem* txtItem = dynamic_cast<PicTextItem*>(item);
if(txtItem->sourceType() != SourceType::IMAGE && txtItem->sourceType() != SourceType::CODE ...) {
    lastSelectedTxtItem = txtItem;
}

如果场景中包含非 PicTextItem 派生类的 QGraphicsItem,dynamic_cast 返回 null,直接解引用 txtItem->sourceType() 崩溃。

6. onBtnItemConfigClicked() — dynamic_cast 后无空检查

文件: testprintwidget.cpp:1042-1043

auto item = dynamic_cast<PicTextItem*>(selectedItems[0]);
if(item->sourceType() == SourceType::COUNTER) {

如果选中的 item 不是 PicTextItem 类型,dynamic_cast 返回 null,直接崩溃。

7. addDateTimeItem() / addScheduleShiftsItem() — dynamic_cast 后无空检查

文件: testprintwidget.cpp:1310-1312

auto item = dynamic_cast<PicTextItem*>(selectItems[0]);
if(item->sourceType() == SourceType::DATETIME) {

同样的问题,testprintwidget.cpp:1338 也存在。

8. onEditItemDone() — C风格强转,无空检查

文件: testprintwidget.cpp:287

PicTextItem *pTextItem = (PicTextItem *)item;
if(pTextItem->sourceType() == SourceType::TEXT)
    pTextItem->setSource(content);

C风格强转不做任何类型检查,如果 item 不是 PicTextItem,访问 sourceType() 是未定义行为。

9. addCounterItem() — dynamic_cast 后无空检查

文件: testprintwidget.cpp:1380

auto item = dynamic_cast<PicTextItem*>(items[index]);
font = f ? *f : item->font();

如果选中的 item 不是 PicTextItem,item->font() 崩溃。


🟡 中风险(特定条件下崩溃)

10. onItemEditorAccepted() — currentItem() 可能返回 null

文件: testprintwidget.cpp:1095

if(itemEditor->currentItem()->source() == SourceType::UNKNOWN) {

currentItem() 可能返回 null 导致崩溃。

11. parseVbfile() 加载 XML 时 m_printSetting 空指针

文件: testprintwidget.cpp:621-622

m_printSetting->setModel(model);
m_printSetting->applyPrintSettingsToSysPara(false);

当加载带有 PrintSettings 的 XML 文件时,loadPrintSetting 为 true 才会执行,但如果 m_printSetting 为 null,会崩溃。

12. on_cbResolution_currentIndexChanged() — 数组越界后的修复逻辑不完整

文件: testprintwidget.cpp:1274-1280

if(index < 0 || int(ARRAY_SIZE(IdxToFontFamily)) <= index) {
    index = std::max(std::min(int(ARRAY_SIZE(IdxToFontFamily) - 1), index), 0);
    ...
}
auto selectedItems = pPicScene->selectedItems();
...
qInfo() << "Selected font family: " << IdxToFontFamily[index];

虽然有边界修正,但 IdxToFontFamily 是一个局部 constexpr 数组,如果 ARRAY_SIZE 宏未正确定义,可能导致越界访问。


🟢 低风险(逻辑问题,不太可能崩溃)

13. pasteCopiedLayer() — 临时对象传入 nullptr

PicTextItem tempSrc(nullptr, nullptr, m_copiedSourceType);

用 nullptr 作为 parent 和 scene 创建临时对象,仅用于类型判断。如果 PicTextItem 构造函数中对 nullptr 做了安全处理,则没问题。

14. onSceneFocusedItemPosChanged() — QString::asprintf 格式字符串不安全

文件: testprintwidget.cpp:1112-1113

ui.m_lblX->setText(QString::asprintf("X:%d", p.x()));
ui.m_lblY->setText(QString::asprintf("Y:%d", p.y()));

使用 asprintf 而非 QString::number(),虽然不会崩溃,但不是最佳实践。


📋 修复建议汇总

优先级 位置 问题 修复方案
P0 saveFile() L435 m_printSetting 空指针 加 if(m_printSetting) 判断
P0 saveFile() L406 qgraphicsitem_cast 返回 null 加 null 检查,跳过非 PicTextItem
P0 onFileOpen() L477 sysPara->devOp 空指针 加 if(sysPara && sysPara->devOp)
P0 getShowSelectItemText() L312 dynamic_cast 无空检查 加 if(txtItem)
P0 onBtnItemConfigClicked() L1042 dynamic_cast 无空检查 加 if(item)
P0 addDateTimeItem() L1310 dynamic_cast 无空检查 加 if(item)
P0 addScheduleShiftsItem() L1338 dynamic_cast 无空检查 加 if(item)
P0 onEditItemDone() L287 C风格强转无检查 改用 dynamic_cast + null 检查
P0 addCounterItem() L1380 dynamic_cast 无空检查 加 if(item)
P0 on_newfileButton_pressed() L1122 m_printSetting 空指针 加 if(m_printSetting)
P1 parseVbfile() L621 m_printSetting 空指针 加 if(m_printSetting)
P1 onItemEditorAccepted() L1095 currentItem() 可能 null 加 null 检查

生成时间

2026-06-29