2026-06-30_18_19 缓存
This commit is contained in:
+16
-7
@@ -250,6 +250,9 @@ void PrintSetting::updateSysStatusToUI(){
|
||||
|
||||
void PrintSetting::on_pushButtonApplyPulseFix_clicked()
|
||||
{
|
||||
if(!sysPara)
|
||||
return;
|
||||
|
||||
pulseNumFix->bindSysPara(sysPara);
|
||||
pulseNumFix->hide();
|
||||
pulseNumFix->show();
|
||||
@@ -596,22 +599,25 @@ void PrintSetting::setEnableSynTriggerSetting(bool flag){
|
||||
|
||||
void PrintSetting::applyPrintSettingsToSysPara(bool showTip)
|
||||
{
|
||||
if(!sysPara)
|
||||
return;
|
||||
|
||||
updateModelFromUI();
|
||||
PrintSettingModel::applyToSysPara(m_model, sysPara);
|
||||
|
||||
if (sysPara) {
|
||||
if (sysPara->devOp) {
|
||||
sysPara->devOp->setHighVoltageAmplitudetoSTM32();
|
||||
sysPara->devOp->writeFpgaCalandar(0);
|
||||
sysPara->devOp->writeFlightCompCtrl(ui->enbFlightCompCtrl->isChecked(),
|
||||
ui->enbAccelDecelPredict->isChecked(), quint32(ui->flightCompWindowCycles->value()));
|
||||
}
|
||||
|
||||
if(sysPara->devOp->writeFpgaPrintPara(true) != -1 && showTip) {
|
||||
QMessageBox box(QMessageBox::Icon::Information, tr("提示"), tr("应用成功"), QMessageBox::Ok, nullptr);
|
||||
auto btn = box.button(QMessageBox::Ok);
|
||||
// btn->setFixedSize(80, 40);
|
||||
if(sysPara->devOp->writeFpgaPrintPara(true) != -1 && showTip) {
|
||||
QMessageBox box(QMessageBox::Icon::Information, tr("提示"), tr("应用成功"), QMessageBox::Ok, nullptr);
|
||||
auto btn = box.button(QMessageBox::Ok);
|
||||
// btn->setFixedSize(80, 40);
|
||||
|
||||
box.exec();
|
||||
box.exec();
|
||||
}
|
||||
}
|
||||
|
||||
if(sysPara)
|
||||
@@ -802,6 +808,9 @@ void PrintSettingModel::applyToSysPara(const PrintSettingModel &model, SysPara *
|
||||
PrintSettingModel PrintSettingModel::fromSysPara(SysPara *sysPara)
|
||||
{
|
||||
PrintSettingModel model;
|
||||
if(!sysPara)
|
||||
return model;
|
||||
|
||||
model.leftRightInverse = sysPara->para.leftRightInverse;
|
||||
model.upDownInverse = sysPara->para.upDownInverse;
|
||||
model.mode0211 = sysPara->para.mode0211;
|
||||
|
||||
@@ -32,6 +32,11 @@ greaterThan(QT_VER_MAJ, 5) | greaterThan(QT_VER_MIN, 9) QT += serialbus
|
||||
greaterThan(QT_MAJOR_VERSION, 4):QMAKE_CXXFLAGS += -fpermissive
|
||||
greaterThan(QT_MAJOR_VERSION, 4):CONFIG += c++11
|
||||
|
||||
CONFIG += qt warn_on debug_and_release
|
||||
QMAKE_CXXFLAGS += -g
|
||||
#QMAKE_POST_LINK += ulimit -c unlimited
|
||||
LIBS += -ldl
|
||||
|
||||
include(qjson/upQJson.pri)
|
||||
|
||||
TEMPLATE = app
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
# BarcodeEditor 健壮性分析报告
|
||||
|
||||
## 涉及文件
|
||||
|
||||
| 文件 | 说明 |
|
||||
|------|------|
|
||||
| [scene/BarcodeEditor.h](../scene/BarcodeEditor.h) | `BarcodeViewModel` 结构体 + `BarcodeEditor` 类声明 |
|
||||
| [scene/BarcodeEditor.cpp](../scene/BarcodeEditor.cpp) | `BarcodeEditor` 类实现 |
|
||||
|
||||
---
|
||||
|
||||
## 🔴 高风险(必定崩溃)
|
||||
|
||||
### 1. `applyCounterConfigToSysPara()` — `m_sysPara->devOp` 无 null 检查
|
||||
**文件**: [BarcodeEditor.cpp:260](../scene/BarcodeEditor.cpp#L260)
|
||||
```cpp
|
||||
m_sysPara->devOp->writeFpgaCalandar(0);
|
||||
```
|
||||
**问题**:函数开头已经检查 `if (!m_sysPara) return;`,但 `m_sysPara` 不为 null 不代表 `m_sysPara->devOp` 不为 null。`devOp` 仍可能为 null,此时直接访问会崩溃。
|
||||
|
||||
---
|
||||
|
||||
## 🟡 中风险(特定条件下逻辑错误)
|
||||
|
||||
### 2. `BarcodeViewModel::saveToXml()` — `QVariant::value<T>()` 类型不一致
|
||||
**文件**: [BarcodeEditor.cpp:515-534](../scene/BarcodeEditor.cpp#L515-L534)
|
||||
```cpp
|
||||
if(vm.type == BARCODE_TYPE_BARCODE) {
|
||||
DlgBarcodeFormatVM barcodeFormat = vm.format.value<DlgBarcodeFormatVM>();
|
||||
// ...
|
||||
}
|
||||
else {
|
||||
DlgQrcodeFormatVM qrcodeFormat = vm.format.value<DlgQrcodeFormatVM>();
|
||||
// ...
|
||||
}
|
||||
```
|
||||
**问题**:如果 `vm.type` 与 `vm.format` 中实际存储的类型不一致,`QVariant::value<T>()` 会返回默认构造对象,不会崩溃但会导致数据丢失。QVariant 本身保证不崩溃。
|
||||
|
||||
---
|
||||
|
||||
### 3. `bindViewModel()` 和 `onContentChanged()` — `m_sysPara` 可能为 null 传给 `makeCounterVM`
|
||||
**文件**: [BarcodeEditor.cpp:135-140](../scene/BarcodeEditor.cpp#L135-L140) 和 [BarcodeEditor.cpp:467-472](../scene/BarcodeEditor.cpp#L467-L472)
|
||||
```cpp
|
||||
m_counterEditor->setViewModel(makeCounterVM(m_sysPara, ...));
|
||||
```
|
||||
**问题**:`m_sysPara` 可能为 null(`bindSysPara()` 未被调用时),虽然 `makeCounterVM` 内部已有 `if(!sysPara) return vm;` 保护,不会崩溃,但返回的空 VM 可能导致计数器显示不正确。
|
||||
|
||||
---
|
||||
|
||||
## 🟢 低风险(健壮性瑕疵,不会崩溃)
|
||||
|
||||
### 4. 构造函数中 `m_dateFormatEditor` / `m_dateReplaceEditor` / `m_counterEditor` 未设置 parent
|
||||
**文件**: [BarcodeEditor.cpp:50-55](../scene/BarcodeEditor.cpp#L50-L55)
|
||||
```cpp
|
||||
m_dateFormatEditor = new DateFormatEditor();
|
||||
m_dateReplaceEditor = new DateReplaceEditor();
|
||||
m_counterEditor = new CounterEditor();
|
||||
```
|
||||
析构中手动 delete,不会内存泄漏。但无 parent 意味着 Qt 父子对象机制不适用,需确保析构顺序正确。
|
||||
|
||||
---
|
||||
|
||||
## 已经做得好的地方
|
||||
|
||||
- ✅ `bindSysPara()` 对 null 输入有检查 + 日志输出
|
||||
- ✅ `applyCounterConfigToSysPara()` 对 `m_sysPara` null 有检查 + 日志输出
|
||||
- ✅ `m_dateFormatEditor` / `m_dateReplaceEditor` / `m_counterEditor` 在构造中 new,析构中 delete,内存管理正确
|
||||
- ✅ 删除标签页使用 `indexOf()` 检查 `-1` 后才移除,不会 remove 不存在的 tab
|
||||
- ✅ `makeCounterVM()` 对 `sysPara` null 有检查,返回默认构造的 VM
|
||||
- ✅ `eventFilter` 中对 `cursor < 0` 做了检查
|
||||
- ✅ `m_barcodeFormatEditor` / `m_qrcodeFormatEditor` 作为成员变量(非指针),构造时自动初始化,永远有效
|
||||
- ✅ `Q_DECLARE_METATYPE` 已声明,QVariant 类型转换安全
|
||||
|
||||
---
|
||||
|
||||
## 📋 需要修复的问题汇总
|
||||
|
||||
| 优先级 | 位置 | 问题 | 修复方案 |
|
||||
|--------|------|------|----------|
|
||||
| **P1** | `BarcodeEditor::applyCounterConfigToSysPara()` L260 | `m_sysPara->devOp` 无 null 检查 | 在访问 `devOp` 前加 `if(m_sysPara->devOp)` 保护 |
|
||||
| **P2** | `bindViewModel()` L134-141 + `onContentChanged()` L466-473 | `m_sysPara` 可能为 null 传给 `makeCounterVM` | 虽然 `makeCounterVM` 自己能处理,但建议加日志或确认 `bindSysPara` 调用时机 |
|
||||
|
||||
---
|
||||
|
||||
## 总结
|
||||
|
||||
BarcodeEditor 类的整体健壮性较好,主要问题仅有一个:
|
||||
|
||||
**`applyCounterConfigToSysPara()` 中 `m_sysPara->devOp` 无 null 检查**,与先前 PrintSetting 报告中发现的同类问题相同,属于 `SysPara` 中 `devOp` 指针使用的普遍模式缺陷。
|
||||
|
||||
---
|
||||
|
||||
## 生成时间
|
||||
2026-06-29
|
||||
@@ -1,3 +1,8 @@
|
||||
#define _GNU_SOURCE // 必须放在所有头文件之前
|
||||
#include <link.h> // dl_iterate_phdr 的声明
|
||||
#include <dlfcn.h> // dladdr 等
|
||||
#include <execinfo.h> // backtrace
|
||||
|
||||
#include <QApplication>
|
||||
#include <QVBoxLayout>
|
||||
#include <InputMethod.h>
|
||||
@@ -20,6 +25,103 @@
|
||||
#include "mainwidget.h"
|
||||
#include "InkJetPrinter.h"
|
||||
#include "Log/filelogger.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <cxxabi.h>
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
#include <execinfo.h>
|
||||
|
||||
QString gAppNameStr = "";//这是个全局变量,用于后续获取当前运行程序的绝对路径
|
||||
|
||||
// 全局变量保存基址
|
||||
static uintptr_t g_base_address = 0;
|
||||
|
||||
// 回调函数:找到当前可执行文件的基址
|
||||
static int find_base_address(struct dl_phdr_info *info, size_t size, void *data) {
|
||||
// 检查是否是主程序(第一个加载的通常是主程序)
|
||||
if (info->dlpi_name == nullptr || info->dlpi_name[0] == '\0') {
|
||||
// 获取第一个段的加载地址(通常是基址)
|
||||
g_base_address = info->dlpi_addr;
|
||||
return 1; // 停止遍历
|
||||
}
|
||||
return 0; // 继续遍历
|
||||
}
|
||||
|
||||
// 获取程序基址的函数
|
||||
uintptr_t get_base_address() {
|
||||
if (g_base_address == 0) {
|
||||
dl_iterate_phdr(find_base_address, nullptr);
|
||||
}
|
||||
return g_base_address;
|
||||
}
|
||||
|
||||
void createStackTraceFile(const char *fileName, const char *appName)
|
||||
{
|
||||
std::ofstream file(fileName);
|
||||
if (!file.is_open()) {
|
||||
std::cerr << "Error opening file: " << fileName << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
void *array[100];
|
||||
size_t size;
|
||||
char **strings;
|
||||
|
||||
size = backtrace(array, 100);
|
||||
if (size == 0) {
|
||||
std::cerr << "No stack frames obtained" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取程序基址(PIE需要)
|
||||
uintptr_t base_addr = get_base_address();
|
||||
|
||||
strings = backtrace_symbols(array, size);
|
||||
file << "Stack trace info:\n";
|
||||
file << "Base address: 0x" << std::hex << base_addr << std::dec << "\n\n";
|
||||
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
file << strings[i] << std::endl;
|
||||
|
||||
// 计算偏移地址:实际地址 - 基址
|
||||
uintptr_t addr = reinterpret_cast<uintptr_t>(array[i]);
|
||||
uintptr_t offset = addr - base_addr;
|
||||
|
||||
char cmd[512];
|
||||
// 使用偏移地址而不是实际地址
|
||||
snprintf(cmd, sizeof(cmd), "addr2line -e %s 0x%lx", appName, offset);
|
||||
|
||||
FILE *fp = popen(cmd, "r");
|
||||
if (fp) {
|
||||
char line[256];
|
||||
while (fgets(line, sizeof(line), fp)) {
|
||||
file << " " << line; // 缩进显示更清晰
|
||||
}
|
||||
pclose(fp);
|
||||
} else {
|
||||
std::cerr << "Failed to run addr2line command" << std::endl;
|
||||
}
|
||||
file << std::endl;
|
||||
}
|
||||
|
||||
free(strings);
|
||||
file.close();
|
||||
}
|
||||
|
||||
void signalHandler(int signum)
|
||||
{
|
||||
// 直接指定固定的路径
|
||||
QString dumpFileName = "/home/plg/doc/dumpfile.txt";
|
||||
QString appName = gAppNameStr;
|
||||
createStackTraceFile(dumpFileName.toUtf8().data(), appName.toUtf8().data());
|
||||
exit(signum);
|
||||
}
|
||||
|
||||
//#define SYS_CN
|
||||
|
||||
/*
|
||||
@@ -72,6 +174,12 @@ int main(int argc, char *argv[])
|
||||
|
||||
QApplication a(argc, argv);
|
||||
|
||||
gAppNameStr = QString::fromUtf8(argv[0]);
|
||||
signal(SIGSEGV, signalHandler);
|
||||
signal(SIGABRT, signalHandler);
|
||||
signal(SIGILL, signalHandler);
|
||||
signal(SIGFPE, signalHandler);
|
||||
|
||||
// 配置日志
|
||||
QString configFileName = ":/conf/config.ini";
|
||||
QSettings* logSettings = new QSettings(configFileName, QSettings::IniFormat, &a);
|
||||
|
||||
@@ -281,7 +281,8 @@ void BarcodeEditor::applyCounterConfigToSysPara()
|
||||
m_sysPara->para.eleEyeClearCntInSynMode = (m_sysPara->para.eleEyeClearCntInSynMode & 0xdf); // CNT2 = current
|
||||
}
|
||||
|
||||
m_sysPara->devOp->writeFpgaCalandar(0);
|
||||
if(m_sysPara->devOp)
|
||||
m_sysPara->devOp->writeFpgaCalandar(0);
|
||||
}
|
||||
|
||||
void BarcodeEditor::onBtnFormatClicked()
|
||||
@@ -457,9 +458,11 @@ void BarcodeEditor::onContentChanged(QString content)
|
||||
else {
|
||||
if(ui->tabWidget->indexOf(m_counterEditor) == -1) {
|
||||
ui->tabWidget->addTab(m_counterEditor, tr(u8"计数器"));
|
||||
m_counterEditor->setViewModel(makeCounterVM(m_sysPara,
|
||||
static_cast<COUNTER_TYPE>(m_vm.counterViewModel.counterType),
|
||||
m_vm.counterViewModel.digitalNum));
|
||||
if(m_sysPara) {
|
||||
m_counterEditor->setViewModel(makeCounterVM(m_sysPara,
|
||||
static_cast<COUNTER_TYPE>(m_vm.counterViewModel.counterType),
|
||||
m_vm.counterViewModel.digitalNum));
|
||||
}
|
||||
}
|
||||
m_counterEditor->setFixedSize(ui->tabBarcode->size());
|
||||
}
|
||||
@@ -594,4 +597,4 @@ void BarcodeEditor::on_cbBoxType_currentIndexChanged(int index)
|
||||
if (index == 0) return;
|
||||
m_qrcodeFormatEditor.setCodeType(ui->cbBoxType->currentText());
|
||||
onQrcodeFormatConfirmed();
|
||||
}
|
||||
}
|
||||
@@ -136,6 +136,10 @@ void PicScene::onFocusItemChanged(QGraphicsItem *newFocusItem, QGraphicsItem *ol
|
||||
return;
|
||||
}
|
||||
|
||||
connect(currFocusItem, &QObject::destroyed, this, [this](){
|
||||
currFocusItem = nullptr;
|
||||
});
|
||||
|
||||
QPoint pos(currFocusItem->x(), currFocusItem->y());
|
||||
emit focusedItemPosChanged(pos);
|
||||
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
#include "setnumdlg.h"
|
||||
#include "ui_setnumdlg.h"
|
||||
#include "SystemManage.h"
|
||||
#include <QDebug>
|
||||
#include "LogInfo.h"
|
||||
|
||||
SystemManage* sysMgr = nullptr;
|
||||
|
||||
SetNumDlg::SetNumDlg(QWidget *parent) :
|
||||
QDialog(parent),
|
||||
|
||||
+8
-4
@@ -432,7 +432,8 @@ void TestPrintWidget::saveFile(){
|
||||
}
|
||||
|
||||
writer.writeEmptyElement("PrintSettings");
|
||||
PrintSettingModel::saveToXml(m_printSetting->model(), writer);
|
||||
if(m_printSetting)
|
||||
PrintSettingModel::saveToXml(m_printSetting->model(), writer);
|
||||
|
||||
writer.writeEndElement(); // 结束根元素 </picscenes>
|
||||
writer.writeEndDocument(); // 结束文档
|
||||
@@ -618,8 +619,10 @@ void TestPrintWidget::parseVbfile(QXmlStreamReader &reader, bool loadPrintSettin
|
||||
QXmlStreamAttributes attrs = reader.attributes();
|
||||
PrintSettingModel model;
|
||||
PrintSettingModel::loadFromXml(model, attrs);
|
||||
m_printSetting->setModel(model);
|
||||
m_printSetting->applyPrintSettingsToSysPara(false);
|
||||
if(m_printSetting) {
|
||||
m_printSetting->setModel(model);
|
||||
m_printSetting->applyPrintSettingsToSysPara(false);
|
||||
}
|
||||
reader.skipCurrentElement();
|
||||
}
|
||||
|
||||
@@ -1119,7 +1122,8 @@ void TestPrintWidget::on_newfileButton_pressed()
|
||||
if (sysPara) {
|
||||
PrintSettingModel defModel = PrintSettingModel::defPrintSettingModel();
|
||||
PrintSettingModel::applyToSysPara(defModel, sysPara);
|
||||
m_printSetting->setModel(defModel);
|
||||
if(m_printSetting)
|
||||
m_printSetting->setModel(defModel);
|
||||
}
|
||||
|
||||
sendButtonClickedSignal(21); //新建文件完成
|
||||
|
||||
Reference in New Issue
Block a user