9.7 KiB
PrintSetting 崩溃风险分析报告
涉及文件
| 文件 | 说明 |
|---|---|
| Printsetting.h | PrintSettingModel 结构体 + PrintSetting 类声明 |
| Printsetting.cpp | PrintSetting 类实现 + PrintSettingModel 静态方法实现 |
| testprintwidget.cpp | TestPrintWidget 中调用 m_printSetting 的代码 |
| InkJetPrinter.cpp | InkJetPrinter 中使用 m_PrintSetting 的代码 |
🔴 高风险(必定崩溃)
1. applyPrintSettingsToSysPara() — sysPara->devOp 在 if 保护块外被访问
void PrintSetting::applyPrintSettingsToSysPara(bool showTip)
{
updateModelFromUI();
PrintSettingModel::applyToSysPara(m_model, sysPara); // L600: 无 null 检查
if (sysPara) { // L602: 有检查
sysPara->devOp->setHighVoltageAmplitudetoSTM32();
sysPara->devOp->writeFpgaCalandar(0);
sysPara->devOp->writeFlightCompCtrl(...);
}
if(sysPara->devOp->writeFpgaPrintPara(true) != -1 && showTip) { // L609: ❌ 在 if(sysPara) 之外!
QMessageBox box(...);
box.exec();
}
if(sysPara)
sysPara->saveParaToFile();
}
问题:
- L600 调用
PrintSettingModel::applyToSysPara(m_model, sysPara)时未检查sysPara是否为 null。 - L609 的
sysPara->devOp->writeFpgaPrintPara(true)在if(sysPara)保护块之外,如果sysPara为 null,直接崩溃。 - L602-L606 虽在
if(sysPara)内,但sysPara->devOp本身也可能为 null。
触发场景:bindSysPara() 未被调用或 sysPara 被意外置空时,用户点击"应用"按钮。
2. PrintSettingModel::applyToSysPara() — sysPara 参数无 null 检查
void PrintSettingModel::applyToSysPara(const PrintSettingModel &model, SysPara *sysPara)
{
sysPara->para.leftRightInverse = model.leftRightInverse; // ❌ 无 null 检查
sysPara->para.upDownInverse = model.upDownInverse;
// ... 后续约 30 行全部直接访问 sysPara->para.xxx
}
问题:整个函数体没有对 sysPara 做 null 检查,直接解引用。如果传入 null,立即崩溃。
调用链:
PrintSetting::applyPrintSettingsToSysPara()→PrintSettingModel::applyToSysPara(m_model, sysPara)PrintSetting::bindSysPara()→PrintSettingModel::fromSysPara(sysPara)(同样无 null 检查,见下文)
3. PrintSettingModel::fromSysPara() — sysPara 参数无 null 检查
PrintSettingModel PrintSettingModel::fromSysPara(SysPara *sysPara)
{
PrintSettingModel model;
model.leftRightInverse = sysPara->para.leftRightInverse; // ❌ 无 null 检查
model.upDownInverse = sysPara->para.upDownInverse;
// ... 后续约 30 行全部直接访问 sysPara->para.xxx
}
问题:与 applyToSysPara() 相同,整个函数体没有对 sysPara 做 null 检查。
调用链:
PrintSetting::bindSysPara()→PrintSettingModel::fromSysPara(sysPara)
4. on_pushButtonApplyPulseFix_clicked() — sysPara 可能为 null
void PrintSetting::on_pushButtonApplyPulseFix_clicked()
{
pulseNumFix->bindSysPara(sysPara); // ❌ sysPara 可能为 null
pulseNumFix->hide();
pulseNumFix->show();
}
问题:未检查 sysPara 是否为 null,直接传给 pulseNumFix->bindSysPara()。
5. TestPrintWidget 中 m_printSetting 空指针解引用(3处)
已在 TestPrintWidget 崩溃风险分析报告 中详述,此处汇总:
| 位置 | 代码 | 问题 |
|---|---|---|
| testprintwidget.cpp:435 | PrintSettingModel::saveToXml(m_printSetting->model(), writer) |
m_printSetting 可能为 null |
| testprintwidget.cpp:621-622 | m_printSetting->setModel(model) / m_printSetting->applyPrintSettingsToSysPara(false) |
m_printSetting 可能为 null |
| testprintwidget.cpp:1122 | m_printSetting->setModel(defModel) |
m_printSetting 可能为 null |
🟡 中风险(特定条件下崩溃)
6. applyPrintSettingsToSysPara() — sysPara->devOp 可能为 null
if (sysPara) {
sysPara->devOp->setHighVoltageAmplitudetoSTM32(); // devOp 可能为 null
sysPara->devOp->writeFpgaCalandar(0); // devOp 可能为 null
sysPara->devOp->writeFlightCompCtrl(...); // devOp 可能为 null
}
问题:虽然检查了 sysPara,但 sysPara->devOp 指针本身可能为 null(取决于 SysPara 的初始化时机)。
7. on_checkEyeTriggerSynPrintEn_clicked() — sysPara 有检查但 comboBoxSyncActType 可能越界
void PrintSetting::on_checkEyeTriggerSynPrintEn_clicked(bool checked)
{
if(sysPara) // ✅ 有 null 检查
{
// ...
if(ui->comboBoxSyncActType->currentIndex() >= ui->comboBoxSyncActType->count()
|| ui->comboBoxSyncActType->currentIndex() == -1)
{
ui->comboBoxSyncActType->setCurrentIndex(0);
}
}
}
问题:comboBoxSyncActType 的 currentIndex() 值为 -1 时的处理是正确的,但如果 comboBox 未正确初始化(count() 为 0),setCurrentIndex(0) 可能无效,但不会崩溃。此处理论上安全,标注为中风险仅供参考。
🟢 低风险(逻辑瑕疵,不太可能崩溃)
8. PrintSettingModel::toString() — 格式说明符类型不匹配
QString PrintSettingModel::toString(const PrintSettingModel &model)
{
QString str = QString::asprintf("LRInverse: %d, ... triggerInterval: %d, ... eleEyeRepeatCnt: %d, ...",
model.triggerInterval, ... model.eleEyeRepeatCnt, ...);
}
问题:model.triggerInterval 和 model.eleEyeRepeatCnt 是 unsigned 类型,但格式说明符用了 %d(有符号)。不会崩溃,但可能输出异常值(如大数字显示为负数)。
9. PrintSettingModel::defPrintSettingModel() — 文件不存在时静默返回默认值
PrintSettingModel PrintSettingModel::defPrintSettingModel()
{
QFile file(DEF_PRINT_SETTINGS_PATH);
if (!file.open(QIODevice::ReadOnly)) {
return PrintSettingModel(); // 静默返回默认构造
}
// ...
}
问题:文件打开失败时没有日志输出,不利于调试。不会崩溃。
10. updateModelFromUI() — 无返回值校验
m_model.encoderPulsePerMm = ui->lineEditTriggerPulsePerMm->text().toFloat();
问题:toFloat() 在输入为空时返回 0.0,不会崩溃。但如果用户输入了非法字符(虽然有 QDoubleValidator),结果可能不符合预期。
11. on_radioButtonEleEyeLevelTrigger_pressed() 等函数中 setEnableSynTriggerSetting 的判断逻辑
void PrintSetting::on_radioButtonEleEyeEdgetTrigger_pressed()
{
setTriggerUI(PRINT_TRIGGER_ELEC_EYE_EDGE);
if(ui->radioButtonSynTriggerExternal->isChecked())
setEnableSynTriggerSetting(true);
else
setEnableSynTriggerSetting(false);
}
问题:这些函数未检查 sysPara 是否为 null 就调用 setTriggerUI,但 setTriggerUI 只操作 m_model 和 UI 控件,不依赖 sysPara,所以安全。
📋 修复建议汇总
| 优先级 | 位置 | 问题 | 修复方案 |
|---|---|---|---|
| P0 | applyPrintSettingsToSysPara() L600 |
sysPara 未检查就传给 applyToSysPara |
在 L600 前加 if(!sysPara) return; |
| P0 | applyPrintSettingsToSysPara() L609 |
sysPara->devOp 在 if 块外访问 |
将 L609-L614 移入 if(sysPara) 块内 |
| P0 | PrintSettingModel::applyToSysPara() L743 |
sysPara 无 null 检查 |
函数开头加 if(!sysPara) return; |
| P0 | PrintSettingModel::fromSysPara() L802 |
sysPara 无 null 检查 |
函数开头加 if(!sysPara) return PrintSettingModel(); |
| P0 | on_pushButtonApplyPulseFix_clicked() L287 |
sysPara 未检查 |
加 if(!sysPara) return; |
| P1 | applyPrintSettingsToSysPara() L603 |
sysPara->devOp 可能 null |
加 if(sysPara->devOp) 判断 |
| P1 | testprintwidget.cpp 多处 |
m_printSetting 可能 null |
加 if(m_printSetting) 判断(共3处) |
崩溃调用链总结
用户点击"应用"按钮
→ PrintSetting::on_pushButtonApply_pressed()
→ PrintSetting::applyPrintSettingsToSysPara(true)
→ PrintSettingModel::applyToSysPara(m_model, sysPara) ← ❌ sysPara 可能 null
→ sysPara->devOp->writeFpgaPrintPara(true) ← ❌ 在 if(sysPara) 外
用户点击"脉冲修正"按钮
→ PrintSetting::on_pushButtonApplyPulseFix_clicked()
→ pulseNumFix->bindSysPara(sysPara) ← ❌ sysPara 可能 null
加载/新建文件
→ TestPrintWidget::saveFile() / parseVbfile() / on_newfileButton_pressed()
→ m_printSetting->model() / setModel() / applyPrintSettingsToSysPara() ← ❌ m_printSetting 可能 null
生成时间
2026-06-29