2、修复若干逻辑bug,具体参考BUG_FIX_REPORT.md Signed-off-by: waiwaylee <waiwaylee@foxmail.com>
20 KiB
20 KiB
雷达数据处理 DLL 逻辑 BUG 分析报告
分析范围:data_process_class_dll/ 下全部源码(不含 Eigen/),以迁移后的当前代码行号为准。
严重级别定义:
- P0:可能导致崩溃、越界读写、内存破坏或长时间运行内存泄漏,建议优先修复。
- P1:在常见异常时序/边界输入下会出错,或属于明显算法逻辑错误。
- P2:健壮性、数值稳定性、状态一致性、功能缺失等问题。
- P3:代码质量/可维护性问题。
1. 内存与生命周期
BUG-01 [P0] 基类没有虚析构函数,工厂按基类指针 delete 派生对象
- 位置:
data_process_class_dll.h:168、data_process_class_dll.cpp:25-32 - 说明:
Data_process_class_dll没有声明虚析构函数,而Data_Process内部包含多个std::vector和若干成员对象。Data_Process_Factory::Destroy()执行delete p时静态类型是基类指针,只会调用基类析构函数,派生类成员(Data_buffer、trust_track、temp_track、Eigen 相关对象等)的析构不会执行,属于未定义行为并造成内存泄漏。 - 建议:在基类中增加
virtual ~Data_process_class_dll() {};同时让工厂支持重复销毁、销毁后返回 nullptr。 - 暂不修复
BUG-02 [P1] Hight_smooth 高度平滑缓存只增不减,长时间运行内存持续增长
- 位置:
track_asso.cpp:890、track_asso_tas.cpp:722、track_asso_direct_tracking.cpp:639 - 说明:每次高度更新都执行
Hight_smooth.push_back(...),从未裁剪或清空。航迹存活时间越长,该 vector 越大;500 条航迹长时间运行时内存会持续增长。 - 建议:仅保留最近
height_win_length个高度值(如resize/erase(begin)后再 push),或改用固定长度std::deque;航迹消亡时随结构体释放。 - 暂不修复
BUG-03 [P2] 工厂单例创建/销毁非线程安全
- 位置:
data_process_class_dll.cpp:15-32 - 说明:
GetB()和Destroy()对静态指针p无任何同步。若宿主在多线程环境调用,可能创建两个实例(泄漏一个)或对同一对象重复销毁。 - 建议:用 C++11
static Data_Process instance;返回地址,或对工厂方法加锁;明确 DLL 接口的线程模型。 - 暂不修复
2. 数组/向量越界
BUG-04 [P0] TAS 输入点迹未限制 Point_Sum <= 150
- 位置:
data_process.cpp:66 - 说明:TWS 分支使用
min(Point_Sum, 150),但 TAS 分支直接data_num = Data_Input[0].Point_Sum并循环读取Data_Input[i]。当协议传入Point_Sum > 150时,会越界读取Data_Input[150]。 - 建议:与 TWS 分支一致,使用
data_num = min(max(Point_Sum,0), 150),并校验Point_Sum >= 0。 - 按建议修复
BUG-05 [P0] Track_to_start.size()-1 在空容器时下溢导致越界
- 位置:
track_init.cpp:534 - 说明:与已发现示例一致。
size()返回size_t,空容器减 1 得到极大值,随后Track_to_start[i]越界。 - 建议:
if (Track_to_start.empty()) return;,或改为for (size_t i = 0; i + 1 < Track_to_start.size(); ++i)。 - 按建议修复,改为
for (size_t i = 0; i + 1 < Track_to_start.size(); ++i)
BUG-06 [P0] track_start_point_num 未校验,取值 0/1/2 或大于 9 时多处越界
- 位置:
track_init.cpp:533,544-545,588-594、track_init_direct_tracking.cpp:316-322 - 说明:重复航迹比较固定访问
Track_to_start[i][1]、[2],三点初始化访问[L-3]/[L-2]/[L-1]。该参数由外部RadarPara传入,若未初始化或配置为 0/1/2,会出现负下标或越界;若大于 9,tmp_track_die会在n>=10时删除临时航迹,逻辑也无法起批。 - 建议:在
track_process_parameters_initial/modify中校验3 <= track_start_point_num <= 9;使用Track_to_start[i].size()作为实际长度并在访问前检查。 - 按建议修复
BUG-07 [P0] 禁止区域个数未限制在 30 以内,外部配置过大时数组越界
- 位置:
track_init.cpp:711(track_prohibite_area_num)、tas_ctrl.cpp:123(TAS_prohibite_area_num) - 说明:循环上界直接使用外部传入的计数,而对应数组固定为
[30]。配置大于 30 时越界读。 - 建议:循环上界改为
min(count, 30),并在参数初始化/修改时拒绝非法计数或截断。 - 暂不修复
BUG-08 [P1] 消亡航迹号输出无数组容量检查
- 位置:
track_die.cpp:24、track_die_tas.cpp:26 - 说明:
Track_die_Index_Output[*Track_die_num_Output-1] = ...不检查数组容量。正常流量下最多 500 条航迹,与MAX_TRACK_NUM一致,但接口没有把容量传入,一旦宿主传入较小数组、或计数被异常修改,就会越界写。 - 建议:接口增加
die_array_capacity参数,或内部保证*Track_die_num_Output < MAX_TRACK_NUM后再写。 - 暂不修改
BUG-09 [P1] Beam_Ctrl 路径中输出计数未初始化/无上界,可能越界写航迹输出数组
- 位置:
data_process.cpp:193-198、tas_ctrl.cpp:74-78 - 说明:
Beam_Ctrl()直接使用宿主传入的Trust_track_num_Output,而tas_ctrl_process不会先清零,tas_target_add会基于旧值自增并写Trust_Track_Output[*Trust_track_num_Output-1]。若调用方未清零或旧值接近MAX_TRACK_NUM,会越界写。 - 建议:
tas_ctrl_process内部保存*count = 0或在每次写入前检查*count < MAX_TRACK_NUM;同时校验指针非空。 - 按建议修改
BUG-10 [P1] 航迹号直接作为数组下标,未校验范围
- 位置:
track_index_mangement.cpp:29 - 说明:
List[(*trust_track)[i].Track_Index-1] = 1,若航迹号不在[1, MAX_TRACK_INDEX]内(异常数据、内存损坏、外部修改),立即越界。 - 建议:写前检查
Track_Index >= 1 && Track_Index <= MAX_TRACK_INDEX,异常航迹号返回错误或跳过。 - 按建议修改
3. 未初始化变量
BUG-11 [P1] Track_Asso_Tas::model_filter 在找不到 TAS 目标时使用未初始化变量
- 位置:
track_asso_tas.cpp:228-232,随后在271/276/280/282等使用 - 说明:
X1/X2/X3/P1/P2/P3/T_track/v_track/r_track/h_track只在Track_Index == tas_track_idx时赋值。若tas_track_idx不存在(例如目标已被消亡、主程序传入失效批号),后续仍用这些未初始化值计算 IMM、距离门限和外推,结果不可预测。MSVC/W4已报 C4701。 - 建议:函数开头初始化这些变量,并在找不到目标时直接 return;上层也应处理“TAS 目标不存在”的返回值。
- 按建议修改
BUG-12 [P1] tas_beam_output 在队列目标不在航迹表中时使用未初始化变量
- 位置:
tas_ctrl.cpp:242-271 - 说明:
H_track、X_now[]只在找到匹配航迹时赋值;若track_clear_all()后队列未清空、或目标已被删除而队列未同步,循环找不到目标,随后asin(H_track/range)、X_now[...]使用未初始化数据。Cppcheck 和 MSVC/W4均报 C4701。 - 建议:找不到目标时立即
open_flag=0并 return;变量声明时初始化。 - 按建议修改
BUG-13 [P2] Data_Process::Work_Parameter 及若干成员在构造后未初始化
- 位置:
data_process.h:28-31,78-95 - 说明:构造函数为空,
Work_Parameter、Beam_num、data_num、TAS_track_idx等未初始化。若宿主在调用track_process_parameters_initial前就调用data_preprocess/track_process/Beam_Ctrl,Work_Parameter.track_start_point_num、Sys_delay、V_MIN/V_MAX等是垃圾值,可能导致起批越界、除零或异常门限。 - 建议:构造函数中对
Work_Parameter进行memset/值初始化并设置安全默认参数;在处理函数入口检查“参数是否已初始化”。 - 暂不修复
BUG-14 [P3] Track_Ind_Mangement::lastest_index 未初始化
- 位置:
track_index_mangement.h:17、track_index_mangement.cpp:33 - 说明:只有空航迹表分支会赋值为 1;如果首次调用时航迹表非空,就会读取未初始化的
lastest_index。 - 建议:声明为
int lastest_index = 0;或增加构造函数初始化。 - 按建议修改
4. 时间戳/时序处理
BUG-15 [P1] TWS 关联在 delta_T <= 0 时仍把点迹标记为已关联并刷新航迹状态
- 位置:
track_asso.cpp:610-691 - 说明:滤波和航迹信息更新在
if (delta_T > 0)内,但Extrapolate_round=0、point_flag=1、associate_point_number++、点迹Use_Flag=1都在 if 之外。重复/乱序时间戳的点仍会“占用”点迹、让航迹看起来已更新,实际状态未更新。 - 建议:
delta_T <= 0时直接跳过该关联候选(或作为无效量测处理),不要标记点迹已使用、不要刷新航迹新鲜度。 - 按建议修改
BUG-16 [P1] TAS 关联完全没有 delta_T > 0 检查
- 位置:
track_asso_tas.cpp:271-335,385-452 - 说明:TAS 路径计算
delta_T后直接进入统计距离和滤波,即使delta_T <= 0也会生成 F/Q 并更新航迹,可能把航迹时间更新到过去。 - 建议:与 TWS 一致,只有
delta_T > 0才允许关联;否则跳过该点。 - 按建议修改
BUG-17 [P1] TAS 外推使用未校验的 latest_timestamp - T_track,负时间差导致反向预测
- 位置:
track_asso_tas.cpp:483-506 - 说明:若
latest_timestamp < T_track(乱序/重复时间戳),delta_T为负,T_track += delta_T*1000会回退航迹时间,IMM F/Q 也按负时间生成。 - 建议:
delta_T = max(0, latest_timestamp - T_track)/1000.0;若为 0 则直接返回或保持原状态。 - 按建议修改
BUG-18 [P1] 卡尔曼初始化及统计距离函数对零/负时间差没有保护
- 位置:
kalman.cpp:13-46,126-130,158-168;调用点track_init.cpp:275,450,593-594、track_init_direct_tracking.cpp:135,271,321-322 - 说明:两点/三点初始化直接除以
T/T1/T2。同一 CPI 重复点、时间戳相等或乱序会产生除零、inf/NaN,随后污染航迹协方差和模型概率。 - 建议:调用前统一校验时间差大于最小阈值(如 >0 或 >1 ms);
kalman_filter_init_2dots/3dots内部对非法时间返回错误。 - 暂不修改
BUG-19 [P1] Bind_speed 对 prt == 0 无保护,而接口说明 PRI 可给 0
- 位置:
kalman.cpp:766-770、data_process_class_dll.h:29 - 说明:
return 150000.0/(freq*prt),当PRI=0时除零;结果传给Round()会把 inf/NaN 转换为未定义整型。 - 建议:
prt <= 0时返回固定安全值或直接返回无效距离;统一约定 PRI 单位与默认值。 - 按建议修改,同时修改接口说明:PRI不可为0
5. 关联门限与滤波算法逻辑
BUG-20 [P1] 统计距离 d 已经是平方形式,门限中又平方了一次
- 位置:
track_asso.cpp:544-546、track_asso_tas.cpp:335、track_asso_direct_tracking.cpp:286、track_init.cpp:221 - 说明:
d_cal_EKF返回的是delta_z^T S^{-1} delta_z(马氏距离平方),后续门限却写成d*d < THRESHOLD*THRESHOLD。例如阈值 3 时本意是d < 9,实际变成d < 3,波门明显偏小。 - 建议:统一改为
d < TRACK_START_THRESHOLD*TRACK_START_THRESHOLD/d < ASSO_THORD*ASSO_THORD。 - 暂不修改
BUG-21 [P1] 近程模型 3 门限因整数除法恒为 0
- 位置:
track_asso.cpp:544-545 - 说明:
ASSO_THORD是 int 宏,ASSO_THORD*ASSO_THORD/1000和/100按整数计算,结果均为 0,导致d3*d3 < 0永远不成立;近距离下模型 3 实际被禁用。 - 建议:写为
ASSO_THORD*ASSO_THORD/1000.0、/100.0,同时按 BUG-20 修正平方关系。 - 按建议修改,但不修改BUG-20
BUG-22 [P1] EKF 方位角残差未按 0/2π 环绕处理
- 位置:
kalman.cpp:265-298,457-492,642-680;凝聚dot_coh.cpp:35,44(work_mode==0分支)、dot_coh_tas.cpp:33,42 - 说明:预测方位被归一化到
[0,2π),但量测方位未归一化,delta_z = Z_mea - Z_pred未做 ±π 环绕。目标跨正北时残差会接近 2π,导致错误拒绝/错误滤波。凝聚中work_mode==0和 TAS 凝聚也直接fabs(angle),未处理 360° 环绕。 - 建议:方位差统一按
wrapToPi()处理;work_mode==0与 TAS 凝聚复用同一环绕角差函数。 - 按建议修改
BUG-23 [P1] IMM 模型概率计算缺少零分母/奇异矩阵保护
- 位置:
track_asso.cpp:157-165,627-647、track_asso_tas.cpp:122-130,406-431、track_asso_direct_tracking.cpp:95-103,352-374 - 说明:
c[0..2]、Possibility1*c[0]+...、det_S都可能为 0 或负;1/sqrt(2*PI*det_S)对负/零行列式产生 NaN。一旦概率变 NaN,后续model_output会把整条航迹状态污染。 - 建议:计算前检查
det_S > eps、分母 > eps;异常时保持上一拍模型概率或回退为等概率{1/3,1/3,1/3}。 - 按建议修改
BUG-24 [P2] EKF 似然只取 3x3 新息协方差左上角 2x2 的行列式
- 位置:
kalman.cpp:515-519(S 为 3x3,但输出只保存 2x2);调用处track_asso.cpp:627-633、track_asso_tas.cpp:406-412、track_asso_direct_tracking.cpp:352-358 - 说明:EKF 量测为距离/方位/径向速度三维,新息协方差 S 是 3x3,但接口
S_filter[2][2]和似然计算只使用二维子块,模型似然不完整。 - 建议:将接口改为 3x3,并采用完整 3 维高斯归一化因子
1/sqrt(pow(2*PI,3)*detS)(若只比较相对大小,也至少应保持三个模型使用相同维数)。 - 按建议修改
BUG-25 [P1] TWS 航迹关联/输出没有排除 TAS 航迹
- 位置:
track_asso.cpp:65-133(输出)、141-228(交互 )、414-570(滤波) - 说明:原代码中有
// if manual_tracking_flag==0的过滤逻辑但被注释掉。当前 TWS 处理会遍历并更新所有航迹,包括Track_Mode==1的 TAS 航迹;TWS 输出循环也会把 TAS 航迹当作point_type=0输出,造成 TAS 航迹被 TWS 点迹错误更新和重复输出。 - 建议:TWS 的交互、关联、输出统一跳过
Track_Mode == 1(或manual_tracking_flag == 1)的航迹;TAS 目标只在 TAS 流程中处理。 - 暂不处理
BUG-26 [P2] 输出航向角使用 atan(y/x) 而不是 atan2
- 位置:
track_asso.cpp:100、track_asso_tas.cpp:66、track_asso_direct_tracking.cpp:59 - 说明:当
vx == 0时除法结果接近 ±inf,现有象限修正逻辑不完整,某些象限会输出负角度或 90° 偏差。 - 建议:统一使用
atan2(X[4], X[1])并归一化到[0,2π)。 - 按建议修改
BUG-27 [P2] asin(height/range) 缺少定义域和零距离保护
- 位置:
track_asso_tas.cpp:54、track_asso_direct_tracking.cpp:48、track_init.cpp:646,673 - 说明:
range为 0 或height > range时,asin参数超出[-1,1]产生 NaN,并输出到Track.Elevation。 - 建议:计算前钳位
h/r到[-1,1],并对r <= eps特殊处理。 - 按建议修改
6. 状态清理与接口一致性
BUG-28 [P1] track_clear_all 清理不彻底,重连后可能输出幽灵航迹/幽灵波束
- 位置:
data_process.cpp:219-229 - 说明:只清空 6 个顶层 vector,未清理:
Dot_Coh::data_input_buff(滑窗凝聚缓存);TAS_Ctrl::tas_target_queue和tas_target_num;last_beam_num(扫描圈判断);Track_Ind_Mangement::lastest_index;- 各关联类的
point_process成员。 清空后若立即调用Beam_Ctrl,TAS 队列仍认为有目标,但trust_track已空,会触发 BUG-12 的未初始化路径并输出错误波束;下一次 TWS 处理也可能输出清空前的缓存点迹。
- 建议:为
Dot_Coh、TAS_Ctrl、Track_Ind_Mangement增加reset(),track_clear_all调用所有 reset,并恢复last_beam_num=INT_MAX。 - 按建议修改
BUG-29 [P2] tracking_stop 后 TAS 队列要到下一次 Beam_Ctrl 才移除
- 位置:
data_process.cpp:260-270、tas_ctrl.cpp:138-162 - 说明:
tracking_stop只清标志位和Track_Mode,不会立即清tas_target_queue。在调用Beam_Ctrl前,队列仍会输出该目标的跟踪波束。 - 建议:
tracking_stop内同步删除 TAS 队列项并更新tas_target_num,或明确接口时序并文档化。 - 暂不修改
BUG-30 [P2] 工作模式枚举与代码分支不一致
- 位置:
data_process_class_dll.h:140(注释:0 进程、1 中程、3 远程)、track_asso.cpp:729-744(按 0/1/2/else 分支) - 说明:注释定义远程模式为 3,但代码按
work_mode==2使用远距数据率;当外部按注释传 3 时,会落入 else 使用近程数据率DATA_RATE_SHORT。 - 建议:统一枚举定义,或代码改为
work_mode==3使用DATA_RATE_FAR。 - 注释有误,修改注释为:0 进程、1 中程、2 远程
BUG-31 [P2] tracking_point 和引导跟踪处理是空实现
- 位置:
data_process.cpp:282-286、data_process_class_dll.h:200-213、track_init_direct_tracking.cpp:11-21 - 说明:
tracking_point直接返回 0;Data_Process没有重写direct_tracking_process,基类默认返回 0;Track_Init_Direct_Tracking::track_init_process_logic也是空函数。若接口已被主程序调用,则相关功能实际未生效。 - 建议:确认这两个接口是否已废弃;若仍需要,补齐实现或至少在文档中明确为未实现并返回错误码。
- 在注释中明确接口未启用,保留空实现
7. 其他逻辑与健壮性
BUG-32 [P2] 凝聚内层循环没有跳过已标记使用的点
- 位置:
dot_coh.cpp:25,148、dot_coh_tas.cpp:25 - 说明:内层只检查当前基准点
loop_of_point的Use_Flag,没有检查被比较点i的Use_Flag。已被凝聚掉的点仍可参与后续比较,甚至反过来把高幅度基准点标记掉。 - 建议:内层同样判断
(*data_input)[i].Use_Flag != 1(以及data_tmp[i])。 - 按建议修改
BUG-33 [P2] 起批/临时航迹关联未校验 delta_T > 0,重复时间戳可能产生非法卡尔曼初始化
- 位置:
track_init.cpp:189,381,450、track_init_direct_tracking.cpp:67,221,271 - 说明:点迹与临时航迹、点迹与航迹头的关联均使用
T_point - T_track_head,未要求正时间差。kalman_filter_init_2dots遇到 0/负 T 会产生除零。 - 建议:在关联条件中显式要求
T_point > T_track_head,且时间差需大于最小步长。 - 暂不修改
BUG-34 [P2] 临时航迹消亡函数在空向量时直接取 [n-1]
- 位置:
track_init.cpp:694-695、track_init_direct_tracking.cpp:417-418 - 说明:
int n = (*Iter).size();后立即(*Iter)[n-1]。正常流程每条临时航迹至少 1 个点,但没有防御;一旦出现空内层向量,n-1为负并越界。 - 建议:先判断
n > 0,空向量直接删除。 - 按建议修改
BUG-35 [P3] 航迹号复用逻辑漏掉 MAX_TRACK_INDEX
- 位置:
track_index_mangement.cpp:44,56 - 说明:回绕查找循环写作
i < MAX_TRACK_INDEX,因此 500 号航迹永远不会被复用;与第一段i <= MAX_TRACK_INDEX不一致。 - 建议:两处回绕循环改为
i <= MAX_TRACK_INDEX。 - 按建议修改
BUG-36 [P3] TAS 波束关闭时只清 open_flag,其他字段保留旧值
- 位置:
tas_ctrl.cpp:277-284 - 说明:当
tas_target_queue[0].empty_flag==0时,仅设置Tracking_beam->open_flag=0,Range/Azi/Elev/type/TAS_track_index保留上一拍内容。主程序若只按open_flag判断则无问题,但字段语义不清晰。 - 建议:关闭时同时清零
type/Range/Azi/Elev/TAS_track_index。 - 暂不修改
BUG-37 [P3] 部分结构体局部变量未完整初始化
- 位置:
track_init.cpp:80,598、track_init_direct_tracking.cpp:325 - 说明:
Temp_track temp_track_tmp、Trust_Track trust_track_tmp的P矩阵等字段未显式初始化。当前流程部分字段未被读取,但依赖调用顺序;后续维护容易读到垃圾值。 - 建议:使用值初始化
Temp_track tmp = {};或为结构体提供构造函数/init()统一初始化所有字段。 - 按建议修改
建议修复顺序
- 先修 P0:BUG-01、BUG-04、BUG-05、BUG-06、BUG-07、BUG-11、BUG-12。
- 再修 P1 时间与关联逻辑:BUG-15~BUG-23、BUG-25、BUG-28。
- 最后处理数值稳定性、状态一致性和未启用功能:BUG-24、BUG-26~BUG-37。
说明:
track_asso_direct_tracking.cpp和track_init_direct_tracking.cpp当前未加入 CMake 构建(与旧 .pro 一致),其中问题与主流程同类问题重复,修复主流程时可同步修改或暂缓。