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

9.7 KiB
Raw Permalink Blame History

PrintSetting 崩溃风险分析报告

涉及文件

文件 说明
Printsetting.h PrintSettingModel 结构体 + PrintSetting 类声明
Printsetting.cpp PrintSetting 类实现 + PrintSettingModel 静态方法实现
testprintwidget.cpp TestPrintWidget 中调用 m_printSetting 的代码
InkJetPrinter.cpp InkJetPrinter 中使用 m_PrintSetting 的代码

🔴 高风险(必定崩溃)

1. applyPrintSettingsToSysPara() — sysPara->devOp 在 if 保护块外被访问

文件: Printsetting.cpp:600-609

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 检查

文件: Printsetting.cpp:743-799

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 检查

文件: Printsetting.cpp:802-845

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

文件: Printsetting.cpp:287-290

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

文件: Printsetting.cpp:603-606

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 可能越界

文件: Printsetting.cpp:302-340

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() — 格式说明符类型不匹配

文件: Printsetting.cpp:849-856

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() — 文件不存在时静默返回默认值

文件: Printsetting.cpp:860-873

PrintSettingModel PrintSettingModel::defPrintSettingModel()
{
    QFile file(DEF_PRINT_SETTINGS_PATH);
    if (!file.open(QIODevice::ReadOnly)) {
        return PrintSettingModel();   // 静默返回默认构造
    }
    // ...
}

问题:文件打开失败时没有日志输出,不利于调试。不会崩溃。


10. updateModelFromUI() — 无返回值校验

文件: Printsetting.cpp:114-170

m_model.encoderPulsePerMm = ui->lineEditTriggerPulsePerMm->text().toFloat();

问题:toFloat() 在输入为空时返回 0.0,不会崩溃。但如果用户输入了非法字符(虽然有 QDoubleValidator),结果可能不符合预期。


11. on_radioButtonEleEyeLevelTrigger_pressed() 等函数中 setEnableSynTriggerSetting 的判断逻辑

文件: Printsetting.cpp:310-325

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