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

150 lines
6.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# TestPrintWidget 崩溃风险分析报告
## 🔴 高风险(必定崩溃)
### 1. `saveFile()` — `m_printSetting` 空指针解引用
**文件**: [testprintwidget.cpp:435](../testprintwidget.cpp#L435)
```cpp
PrintSettingModel::saveToXml(m_printSetting->model(), writer);
```
`m_printSetting` 在 `setPrintSettingWidget()` 调用前为 `nullptr`。如果用户在 `setPrintSettingWidget()` 被调用之前就触发了保存,程序会崩溃。虽然 `InkJetPrinter.cpp:104` 在构造时调用了它,但如果构造顺序出现问题或 `m_PrintSetting` 尚未初始化,就会崩溃。
### 2. `saveFile()` — `qgraphicsitem_cast` 返回 null 后解引用
**文件**: [testprintwidget.cpp:406](../testprintwidget.cpp#L406)
```cpp
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](../testprintwidget.cpp#L477)
```cpp
sysPara->devOp->fpgaWr(0xa4b0, (unsigned char *)&SpecialVarEnable, 1);
```
- `sysPara` 可能为 null(`bindSysPara()` 未被调用时)
- `sysPara->devOp` 也可能为 null
### 4. `on_newfileButton_pressed()` — `m_printSetting` 空指针解引用
**文件**: [testprintwidget.cpp:1122](../testprintwidget.cpp#L1122)
```cpp
m_printSetting->setModel(defModel);
```
同样的问题,`m_printSetting` 可能为 null。
### 5. `getShowSelectItemText()` — `dynamic_cast` 后无空检查
**文件**: [testprintwidget.cpp:312-317](../testprintwidget.cpp#L312-L317)
```cpp
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](../testprintwidget.cpp#L1042-L1043)
```cpp
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](../testprintwidget.cpp#L1310-L1312)
```cpp
auto item = dynamic_cast<PicTextItem*>(selectItems[0]);
if(item->sourceType() == SourceType::DATETIME) {
```
同样的问题,`testprintwidget.cpp:1338` 也存在。
### 8. `onEditItemDone()` — C风格强转,无空检查
**文件**: [testprintwidget.cpp:287](../testprintwidget.cpp#L287)
```cpp
PicTextItem *pTextItem = (PicTextItem *)item;
if(pTextItem->sourceType() == SourceType::TEXT)
pTextItem->setSource(content);
```
C风格强转不做任何类型检查,如果 item 不是 PicTextItem,访问 `sourceType()` 是未定义行为。
### 9. `addCounterItem()` — `dynamic_cast` 后无空检查
**文件**: [testprintwidget.cpp:1380](../testprintwidget.cpp#L1380)
```cpp
auto item = dynamic_cast<PicTextItem*>(items[index]);
font = f ? *f : item->font();
```
如果选中的 item 不是 PicTextItem,`item->font()` 崩溃。
---
## 🟡 中风险(特定条件下崩溃)
### 10. `onItemEditorAccepted()` — `currentItem()` 可能返回 null
**文件**: [testprintwidget.cpp:1095](../testprintwidget.cpp#L1095)
```cpp
if(itemEditor->currentItem()->source() == SourceType::UNKNOWN) {
```
`currentItem()` 可能返回 null 导致崩溃。
### 11. `parseVbfile()` 加载 XML 时 `m_printSetting` 空指针
**文件**: [testprintwidget.cpp:621-622](../testprintwidget.cpp#L621-L622)
```cpp
m_printSetting->setModel(model);
m_printSetting->applyPrintSettingsToSysPara(false);
```
当加载带有 PrintSettings 的 XML 文件时,`loadPrintSetting` 为 true 才会执行,但如果 `m_printSetting` 为 null,会崩溃。
### 12. `on_cbResolution_currentIndexChanged()` — 数组越界后的修复逻辑不完整
**文件**: [testprintwidget.cpp:1274-1280](../testprintwidget.cpp#L1274-L1280)
```cpp
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
```cpp
PicTextItem tempSrc(nullptr, nullptr, m_copiedSourceType);
```
用 `nullptr` 作为 parent 和 scene 创建临时对象,仅用于类型判断。如果 PicTextItem 构造函数中对 nullptr 做了安全处理,则没问题。
### 14. `onSceneFocusedItemPosChanged()` — `QString::asprintf` 格式字符串不安全
**文件**: [testprintwidget.cpp:1112-1113](../testprintwidget.cpp#L1112-L1113)
```cpp
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