6.6 KiB
TestPrintWidget 崩溃风险分析报告
🔴 高风险(必定崩溃)
1. saveFile() — m_printSetting 空指针解引用
PrintSettingModel::saveToXml(m_printSetting->model(), writer);
m_printSetting 在 setPrintSettingWidget() 调用前为 nullptr。如果用户在 setPrintSettingWidget() 被调用之前就触发了保存,程序会崩溃。虽然 InkJetPrinter.cpp:104 在构造时调用了它,但如果构造顺序出现问题或 m_PrintSetting 尚未初始化,就会崩溃。
2. saveFile() — qgraphicsitem_cast 返回 null 后解引用
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 空指针解引用
sysPara->devOp->fpgaWr(0xa4b0, (unsigned char *)&SpecialVarEnable, 1);
sysPara可能为 null(bindSysPara()未被调用时)sysPara->devOp也可能为 null
4. on_newfileButton_pressed() — m_printSetting 空指针解引用
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风格强转,无空检查
PicTextItem *pTextItem = (PicTextItem *)item;
if(pTextItem->sourceType() == SourceType::TEXT)
pTextItem->setSource(content);
C风格强转不做任何类型检查,如果 item 不是 PicTextItem,访问 sourceType() 是未定义行为。
9. addCounterItem() — dynamic_cast 后无空检查
auto item = dynamic_cast<PicTextItem*>(items[index]);
font = f ? *f : item->font();
如果选中的 item 不是 PicTextItem,item->font() 崩溃。
🟡 中风险(特定条件下崩溃)
10. onItemEditorAccepted() — currentItem() 可能返回 null
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