Files
StandardSence/StandardScene代码审查报告.md
T
2026-06-14 11:19:15 +08:00

268 lines
16 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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.
# StandardScene 代码审查报告
> 审查对象:`E:\Work\Core\Simple-FR\StandardSence`StandardScene.Core / StandardScene.Devices / StandardScene.Protocol.VDA5050
> 审查方式:全量反模式扫描(ripgrep)+ 关键文件精读 + 编译告警分类(dotnet build --no-incremental
> 目标框架:`net8.0-windows`(最终目标 `net8.0`
> 报告日期:2026-06-09
---
## 一、审查范围与方法
- **代码规模**113 个 `.cs` 文件;最大文件 `WebApi.cs`2661 行)、`AbstractLoopMission.cs`1858 行)。
- **扫描维度**:并发/线程、异常处理、报文解析边界、资源管理、配置硬编码、日志、UI/业务耦合、安全、编译告警。
- **证据标注**
- `精读确认`:已逐行读取、行号精确。
- `扫描命中`:ripgrep 命中文件级,行号待整改时逐一核对。
---
## 二、总体评价与子系统评分
| 子系统 | 评分 | 说明 |
|---|---|---|
| 设备驱动(StandardScene.Devices·新) | ★★★★☆ | `ModbusDoorController` 工程化优秀,可作团队样板 |
| TCP 基础设施(AsyncTcpClient) | ★★★★☆ | 锁/陈旧回调防护/重连完善,少量瑕疵 |
| Coders(重构后) | ★★★★☆ | 本轮已去重,结构清晰 |
| CarTypes 车型族 | ★★☆☆☆ | 巨类、async void、空 catch、硬编码集中 |
| 任务族 Missions | ★★☆☆☆ | Thread.Abort、while(true)+Sleep、状态机分散 |
| 充电 Charge | ★★☆☆☆ | 实时报文路径越界风险、UDP 线程模型粗放 |
| VDA5050 协议 | ★★☆☆☆ | 硬编码 IP、async void、throw ex、Console 日志 |
| WebApi(老 Nancy | ★☆☆☆☆ | 2661 行上帝文件、无鉴权反射调用、模板代码爆炸 |
| Commons / 公共层 | ★★☆☆☆ | 上帝工具类、重复实现、隐性 bug |
**核心判断**:技术债**集中在旧模块**CarTypes / Missions / Charge / VDA5050 / WebApi / Commons);**新写模块**Devices、AsyncTcpClient)质量明显更高,说明团队具备写好代码的能力,债务主要是历史遗留。整改应"以新模块为范本、按子系统收敛旧债"。
---
## 三、问题严重级别汇总
| 级别 | 含义 | 主要条目 |
|---|---|---|
| **P0 阻断** | .NET8 下会崩溃/失效,或存在安全风险 | Thread.Abort 被吞、WebApi 无鉴权反射、实时报文越界 |
| **P1 高危** | 生产环境易触发故障/难排障 | 硬编码 IP、async void+throw、空 catch、HttpClient 滥用 |
| **P2 结构** | 可维护性/扩展性差 | 上帝类、重复代码、Console 日志、UI/业务耦合 |
| **P3 整洁** | 编译告警与代码卫生 | 45 项告警(重复 using、未用字段、隐藏成员等) |
---
## 四、P0 阻断级问题
### P0-1 `Thread.Abort()` 在 .NET8 必抛异常且被静默吞掉(线程停不掉)
`Thread.Abort()` 在 .NET8 抛 `PlatformNotSupportedException`(告警 SYSLIB0006,共 14 条/双配置)。多处 `Abort()` 外层是空 `catch{}`,导致**异常被吞、线程实际未停止**——任务"停止"后后台线程仍在跑,造成重复下发、资源泄漏、状态错乱。
精读确认命中点:
| 文件 | 行 |
|---|---|
| `StandardScene.Core/Chained/AbstractLoopMission.cs` | 1314 `_strategyThread?.Abort()`、1329 `_logicThread?.Abort()` |
| `StandardScene.Core/Charge/StandardChargeMission.cs` | 681 `myThread?.Abort()`、684 `ChargeThread?.Abort()` |
| `StandardScene.Core/Scheduler/SecuritySignalMission.cs` | 176 `myThread?.Abort()` |
| `StandardScene.Core/Scheduler/NodeIsEnableMission.cs` | 121 `myThread?.Abort()` |
| `StandardScene.Core/Scheduler/HeartBeatMission.cs` | 68 `_myThread?.Abort()` |
| `StandardScene.Core/Chained/AbstractChainedDeliveryMission.cs` | 1606 `myThread.Abort()` |
典型代码(`AbstractLoopMission.cs:1309``精读确认`):
```1309:1334:E:\Work\Core\Simple-FR\StandardSence\StandardScene.Core\Chained\AbstractLoopMission.cs
public virtual void StopLoop()
{
try
{
_strategyRunning = false;
_strategyThread?.Abort();
_strategyThread = null;
...
}
catch { }
}
```
**修复方向**:改为**协作式停止**——已有 `_strategyRunning/_logicRunning` 布尔标志,循环体应周期检查该标志退出;线程创建用 `IsBackground=true`,停止时 `flag=false` 后 `Join(timeout)`。删除所有 `Abort()`。对阻塞型循环用 `CancellationToken` + 可中断等待(`Task.Delay(token)` / `ManualResetEventSlim.Wait(token)`)替代 `Thread.Sleep`。参考 `ModbusDoorController` 的 `CancellationTokenSource` 范式。
---
### P0-2 WebApi 反射接口:无鉴权远程调用任意方法(RCE 级风险)
`StandardScene.Core/WebApi.cs``精读确认`272314 / 332368)暴露:
```272:296:E:\Work\Core\Simple-FR\StandardSence\StandardScene.Core\WebApi.cs
Get("/car_reflection/execute/{id}/{method}", parameters =>
{
...
methodInfo = car.GetType().GetMethod((string)parameters.method);
...
return ExecuteMethod(methodInfo, car, queryParams);
});
```
`mission_reflection/execute/{id}/{method}` 同款。问题:**通过 HTTP 即可按名反射调用 Car/Mission 上任意 public 方法**,无身份校验、无方法白名单、无危险方法拦截。结合 `GET` 语义,配置不当会暴露在内网甚至外网,构成命令执行级攻击面。
**修复方向**
1. 最小化:加访问令牌/来源 IP 限制(中间件统一校验)。
2. 方法白名单:仅允许标注了 `[MethodMember]`(或新增 `[WebInvokable]`)的方法被反射调用;拒绝其余。
3. 语义化:执行类操作改 `POST`;统一错误响应封装(见 P2-2)。
---
### P0-3 实时报文解析按固定下标取值、缺长度校验(IndexOutOfRange 崩溃)
对比发现两条解析路径**风险等级不同**:
- ✅ **正确范本**`StandardScene.Core/Charge/CommunicationMessageService.cs``精读确认`)在取下标前先校验 `parts.Length < 30 / < 10`198、276 行),再访问 `bytes[28]` 等,越界已被防住。
- ❌ **风险路径**:实时 UDP/回调路径按固定下标直接取值,未见等价长度校验(`扫描命中`):
- `StandardScene.Core/ChargeUdpService.cs``message[28]` 等)
- `StandardScene.Devices/Charge/PCBChargeStation.cs``OnUdpMessage` 中 `message[1]`
- `StandardScene.Core/ChargeStationType/MuXingChargeStation.cs`
设备掉线/半包/异常帧时,直接 `IndexOutOfRangeException`,且若发生在 UDP 接收线程会拖垮整条接收链路。
**修复方向**:所有报文解析入口统一"先校验长度(与帧头/类型匹配)再取值",越界返回 null 并 `Diagnosis.Log` 记录原始帧;抽出 `ChargeFrameParser` 复用 `CommunicationMessageService` 的安全解析。
---
## 五、P1 高危问题
### P1-1 配置硬编码(IP/URL/路径),多 AGV/换环境必失效(`扫描命中` 14 文件)
最典型(`精读确认``StandardScene.Protocol.VDA5050/VDACar/VDA5050Car.cs:150`
```150:168:E:\Work\Core\Simple-FR\StandardSence\StandardScene.Protocol.VDA5050\VDACar\VDA5050Car.cs
public async void GetVDA5050StateFromC()
{
try
{
//string jsonResponse1 = await hc.GetStringAsync($"http://{this.address}:8008/getStat");
string jsonResponse1 = await hc.GetStringAsync($"http://192.168.2.1:8008/getStat");
...
}
catch (Exception ex)
{
}
}
```
把按车 `this.address` 的写法**注释掉、写死 `192.168.2.1`**——多 AGV 场景必然全部打到同一地址;外加空 catch 吞错,故障"静默"。其余命中:`Kiva.cs`/`Forklift.cs``192.168.2.1:8008`)、`Map.cs``127.0.0.1:4321`)、`LoopMission.cs`(西门子 PLC IP)、`TransportDeliveryCallbacks.cs`(回调 URL)、`StandardCADTool.cs`Windows 盘符路径)等。
**修复方向**:抽 `scene.json`/配置中心统一注入;禁止业务代码内联端点;`StandardCADTool` 路径改相对/可配置。
### P1-2 `async void` + 在其中 `throw`(CA2200 失栈)→ 进程级崩溃风险
- `Kiva.cs:619` `public new async void ForceStop()``精读确认`):`async void`catch 内 `MessageBox.Show`UI 耦合),最外层 `Console.WriteLine(e); throw;`——`async void` 抛出的异常无法被调用方捕获,直接打到 `SynchronizationContext`/线程池,可致进程崩溃。`new` 还隐藏基类 `ForceStop`CS0114)。
- `VDA5050Car.cs:240` `throw ex;``精读确认`)破坏原始堆栈(CA2200,全仓 4 条)。`DummyCar.cs` 同款。
- `async void` 在 CarTypes/Charge/VDA5050/CAD 等多文件广泛存在(`扫描命中`)。
**修复方向**:事件处理器之外一律 `async Task`;确需 `async void` 的入口用 `try/catch` 兜底并 `Diagnosis.Log`,不得外抛;`throw ex;` → `throw;`。
### P1-3 空 `catch{}` 静默吞异常(`扫描命中` 10 文件)
`Kiva.cs`、`VDA5050Car.cs`、`FLChargeStation.cs`、`AbstractLoopMission.cs`、`Commons.cs`、`AsyncTcpClient.cs`、`LoopViewer.cs` 等。`Kiva.cs:606`、`VDA5050Car.cs:165` 为典型业务路径空 catch。
> 注:`AsyncTcpClient` / `ModbusDoorController` 中环绕 `Close()/Dispose()` 的空 catch 属可接受的清理兜底,应保留但加注释;业务路径空 catch 必须改为记录日志。
### P1-4 同步阻塞调用 `.Result/.Wait()/GetAwaiter().GetResult()``扫描命中` 7 文件)
`ButtonMission.cs`、`DoorMission.cs`、`VDA5050Car.cs` 等。`Kiva.cs:635 status.programs.task.Wait()``精读确认`)在 UI/线程上下文易死锁。**修复**:异步链路打通,避免 sync-over-async。
### P1-5 `new HttpClient()` 反复实例化(Socket 耗尽)(`扫描命中`
`Forklift.cs`/`Kiva.cs`/`VDA5050Car.cs`/`WebApi.cs` 等频繁 `new HttpClient`。**修复**:单例或 `IHttpClientFactory`/`SocketsHttpHandler`(设 `PooledConnectionLifetime`)。
---
## 六、P2 结构 / 质量问题
### P2-1 `Commons.cs` 上帝工具类(`精读确认`
- `AddOrUpdateCarField/SiteField/MissionField` "ContainsKey→Remove+Add / else Add" 模板**重复 4 份**,应为 `dict[key]=value`。
- `AddOrUpdateTag` 名为 update 实为 add(更新逻辑被注释),重复键会抛错,命名误导。
- `CarValue`:存在 `electricCurrent` 时**忽略入参 key** 直接返回,疑似 bug。
- `GoSite` catch 内 `Console.WriteLine + Thread.Sleep(3000)`,注释写"重新执行"但**并未真正重试**。
- 调度 `NearestTask`(约 398–538)巨函数、深嵌套、大段 `#region ObsoleteCode` 注释代码、魔法优先级 `Priority=50`。
### P2-2 `WebApi.cs` 2661 行上帝文件(`精读确认`
错误响应 `new { Success=false, Code=500, Data="null", Message=... }` 模板**复制几十处**;路由全堆一个文件。**修复**:抽 `ApiResult.Fail/Ok` 帮助器;按资源拆分路由模块;老接口归入 `WebApi.Core(deprecated)` 并规划迁移。
### P2-3 日志体系不统一(`扫描命中` 22 文件 `Console.WriteLine`
与 `Diagnosis.Log` 混用。`ModbusDoorController` 已全程 `Diagnosis.Log`,应作为统一范式推广;禁用 `Console.WriteLine` 于业务代码。
### P2-4 UI 与业务耦合(`扫描命中`
`MessageBox.Show` 出现在 `Commons.cs`TrafficControl.OnDeadLock)、`Kiva.cs:648`、`DoorManager.cs`、`ButtonBoxManager.cs` 等业务/管理类中。**修复**:业务层只发事件/日志,弹窗交由 UI 层(后续 migu 平台)。
### P2-5 `while(true)+Thread.Sleep` 忙等/阻塞(`扫描命中` 13 文件)
`Forklift.cs`、`StandardChargeMission.cs`、`ChargeUdpService.cs`、`VDA5050Car.cs` 等。**修复**:改 `CancellationToken`+可中断等待或定时器;与 P0-1 协作式停止一并处理。
### P2-6 AsyncTcpClient 细节(`精读确认`
- `Send` 失败抛 `InvalidProgramException`(异常类型不当,应 `InvalidOperationException`/自定义)。
- `HandleDatagramWritten` 调 `EndWrite` 无 try,写失败异常落到线程池无人观测。
- `uint on = 1;` 未使用字段(CS0414)。
---
## 七、编译告警分类(全量,双配置合计 90 实例 ≈ 45/配置)
| 告警码 | 数量 | 含义 | 处置 |
|---|---|---|---|
| CS0108 | 16 | 隐藏继承成员未加 `new` | 显式 `new`/`override` 或改名 |
| CS4014 | 14 | 调用未 `await`(即发即弃) | 显式 `await` 或 `_ =` 并说明 |
| CS0414 | 14 | 私有字段赋值但从未使用 | 删除 |
| SYSLIB0006 | 14 | `Thread.Abort` 已弃用 | 见 **P0-1** |
| CS0105 | 6 | 重复 using | 删除 |
| CS0162 | 6 | 不可达代码 | 清理 |
| CS0168 | 6 | 变量声明未用 | 删除 |
| CA2200 | 4 | `throw ex` 失栈 | 改 `throw;` |
| CS8321 | 2 | 局部函数未用 | 删除(如 VDA5050Car `monitor()` |
| CS0169 | 2 | 字段从未使用 | 删除 |
| CS0114 | 2 | 隐藏继承成员(如 ForceStop | `override`/`new` |
| CS0219 | 2 | 变量赋值未用 | 删除 |
| CS0649 | 2 | 字段从未赋值 | 初始化或删除 |
---
## 八、分子系统评述(摘要,详版见架构方案)
- **CarTypes**`BasicCarFields/SiteFields/TrackFields/PlanFields` 字段袋设计合理(`BasicFields.cs``CarLength/CarWidth` 默认 `-1` 作"未配置"哨兵,已被避障 Coder 正确利用);但具体车型(Kiva/Forklift/VDA5050Car)是巨类,混杂通信、状态、UI、调度,async void/空 catch/硬编码集中。
- **Coders**:本轮已完成磁导航统一与避障去重(`AvoidanceParamCoder` 4 参 + `AvoidanceParamLWCoder` 2 参),结构清晰,建议继续把车型内联 Coder 收敛到 `CommonTrackCoders`。
- **Missions**Chained/InterLock/Scheduler 线程模型粗放(裸 `new Thread`+`Abort`+`while(true)`),状态机散落字符串 `status.status`。建议统一 `MissionRunnerBase`CancellationToken + 状态枚举)。
- **Charge**:解析存在"安全范本"与"风险路径"并存(见 P0-3);UDP 服务与 Mission 线程耦合。
- **Devices(新)**`ModbusDoorController` 优秀;唯一瑕疵是用析构函数兜底 `Disconnect`(在 GC 线程取锁+`Wait`,有风险),应实现 `IDisposable` 显式释放。
- **VDA5050**MQTT/HTTP 异步用法不规范(async void、throw ex、硬编码 IP、Console 日志),状态处理 `ProcessCacheAndSendOrderMessage` 内大量 Console。
- **WebApi**:见 P0-2 / P2-2,最高优先级重构对象。
---
## 九、正面样板(建议作为团队基线)
1. `StandardScene.Devices/Door/ModbusDoorController.cs``CancellationTokenSource` 协作式停止、`lock` 线程安全、变更检测(`_lastSentControl`)、重连节流、统一 `Diagnosis.Log`、资源清理。
2. `StandardScene.Core/TCP/AsyncTcpClient.cs`:锁保护、陈旧回调防护、自动重连。
3. `StandardScene.Core/Charge/CommunicationMessageService.cs`:报文解析前置长度校验(安全解析范本)。
---
## 十、整改路线图
**第 1 批(P0,本次执行)**
1. Thread.Abort → 协作式停止(6 文件 8 处)。
2. WebApi 反射 execute 加来源校验 + `[MethodMember]` 白名单。
3. 充电实时报文路径补长度校验(复用安全解析)。
**第 2 批(P1**
4. 硬编码端点配置化(VDA5050/Kiva/Forklift/Map/Loop/CAD)。
5. `async void`→`Task`、`throw ex`→`throw`、业务空 catch 加日志。
6. HttpClient 单例化;sync-over-async 拆解。
**第 3 批(P2/结构)**
7. `ApiResult` 帮助器 + WebApi 拆分;`Commons` 拆服务、修 `CarValue`/`GoSite`/`AddOrUpdate`。
8. 统一 `Diagnosis.Log`UI 解耦;`MissionRunnerBase` 统一线程/状态机。
**第 4 批(P3 卫生)**
9. 清 45 项告警(重复 using、未用字段、不可达代码、隐藏成员)。
---
## 附录:扫描方法
- 反模式:`rg` 扫描 `Thread.Abort` / `catch\s*\{\s*\}` / `throw ex;` / `async void` / `\.Result|\.Wait\(\)` / 硬编码 IP / `Console.WriteLine` / `while\s*\(\s*true\s*\)` / `new HttpClient` / `MessageBox.Show` / 魔法下标。
- 告警:`dotnet build --no-incremental` → `_buildwarnings.txt` → 按告警码聚合计数。
- 精读:AsyncTcpClient、Commons、CommunicationMessageService、VDA5050Car、WebApi、Kiva、AbstractLoopMission、ModbusDoorController、BasicFields 等。