E-02审计闭环:timeSync分片修复留档(4a1605b台架A/B 28.6s→109ms)与E-02专项回归探针
This commit is contained in:
@@ -39,7 +39,7 @@ E-60"write_enable WRTC2 与手册矛盾"经三方复核(手册表头 D7~D0 顺
|
||||
|
||||
| 编号 | 子系统 | 一句话 |
|
||||
|---|---|---|
|
||||
| E-02 | net 执行器 | **队列头阻塞**:任一消费者的阻塞 recv(30s)在 netTask 上下文空转 → 全体消费者的队列消息停摆最长 30s(事件仍处理);FTP 客户端空闲 >30s 即可触发 |
|
||||
| E-02 | net 执行器 | **队列头阻塞**:任一消费者的阻塞 recv(30s)在 netTask 上下文空转 → 全体消费者的队列消息停摆最长 30s(事件仍处理);FTP 客户端空闲 >30s 即可触发。**已修复(2026-09-22)**:lftpd(f8d6e90)/timeSync(4a1605b)两个触发源均改 `net_recv_to` 5ms 分片有界读,台架 A/B 实证(明细见 §3.2) |
|
||||
| E-03 | net 层 | 全局 `s_net_errno` 跨任务覆写竞态(09-21 修复的**残留**):恢复与读取之间隔任务切换,健康连接可被误拆(ui_sink :460 每 10ms 读) |
|
||||
| E-04 | UI 远端推流 | `remo_send` 丢弃 `net_send` 返回值 → 3205B 响应弱网短发送**静默截断**(09-21 事故机制的调用方一侧未闭环) |
|
||||
| E-05 | net 层 | 3 任务直调 `net_socket/net_bind/net_getsockname` 跨任务写 netTask 属主的 socket 表 → alloc/close 交错可双分同一 fd(SPI 铁律未破,表属主破了) |
|
||||
@@ -154,6 +154,10 @@ E-60"write_enable WRTC2 与手册矛盾"经三方复核(手册表头 D7~D0 顺
|
||||
- **模式**:P4 变体(串行化头阻塞,非丢消息)
|
||||
- **影响**:最长 30s 全网队列停摆——uiTask 100Hz 轮询、FTP 收发/accept、timeSync 全部排在队列里得不到处理;事件处理不受影响(等待循环内仍调 `net_poll`,`:1020`),受影响的**恰是队列**;与 E-06 叠加 → PASV 假 425;STOR 上传方向芯片 2KB 缓冲满 + 重传 8×500ms=4s 耗尽 → 必断
|
||||
- **修复方向**:消费端阻塞 recv 改 `DONTWAIT` 分片 + 调用方重投 + 总超时(ui_sink 模式推广到 lftpd/timeSync);或 `net_process_messages` 在长阻塞间隙按 tick 继续排空队列;`NET_RECV_TIMEOUT_MS` 按服务可容忍量级分离(既有 P2-8 是本条的子集)
|
||||
- **已修复(2026-09-22,两提交)**:落地方案为方向①的变体——"分片"用**有界阻塞片**而非 DONTWAIT 重投:新增 `net_recv_to` 接口(`msg.timeout_ms` 携带片长;片超时以独立返回码 -2 区分,无跨任务 errno 竞态);调用方累计总预算、片间 `vTaskDelay(1)` 让出 CPU(防 Normal 优先级忙循环饿死 BelowNormal 的 uiTask,M3 实证);5ms 片长 = 其他任务最坏等待(100ms 片下受压帧 ~750ms、5ms 片 ~10ms,`docs/测试说明/链路延迟测试说明.md` §8.3);30s 总预算保持旧超时语义
|
||||
① **lftpd 侧(commit f8d6e90,M3 台架复验)**:`lftpd_inet_read_line`/`lftpd_inet_read` 的 30s 阻塞 recv 改 5ms 分片 + 30s 总预算;M3 压力档(空闲 FTP 半登录态)帧周期 med 17718ms/尖峰 17.7s → **med 65.0ms/max 133.5ms/零尖峰**
|
||||
② **timeSync 侧(commit 4a1605b)**:`time_sync_handle_conn` 单次 30s 阻塞 `net_recv` 改同模式(5ms 片/30s 总预算/跨片累积容忍 TCP 分段/超时留痕 `time_sync: no TIME packet in 30s, drop conn`);产品构建 `@test` 闭环 PASS(Required 全中/Forbidden 零命中)
|
||||
**A/B 台架对照(`test/e02_probe.py`,2026-09-22 13:07~13:16,设备 192.168.1.100)**:挂起客户端连 :8888 后不发数据,2s 后 PC 测 FTP(:21) banner 时延 = 队列响应性——旧固件 **28554ms**(队头冻结;设备日志实证芯片侧握手与 MCU 侧 "connection received" 相隔 27s;旧代码 30s 后静默拆连**零日志**)vs 修复后 **109ms(产品构建)/75ms(测试构建)**;30s 预算耗尽拆连后监听均经 2 次 Trap 09 重试 ~8s 恢复(两侧行为同构,非本修复引入);修复版超时留痕在位、正常路径(8B TIME 包)`wall clock updated` + RTC 回写 + 监听重建全通。(注:旧固件轮的芯片侧监听状态为上次烧录遗留——ST-LINK 仅复位 MCU、CH395F 状态延续,不影响队列冻结证据,冻结主体为旧固件 netTask 的阻塞 recv)
|
||||
|
||||
#### E-03 全局 `s_net_errno` 跨任务覆写竞态(09-21 修复的残留)
|
||||
- **位置**:写方 = `net_socket.c:39` 单全局;netTask 侧 `:362/365/375/385/410` + **notify 值构造 `:419-423`**(`s_notified` 分支读同一全局);6 个队列包装器在**调用方上下文** `:660/758/818/1233/1286/1333`(仅失败路径写);6 个直调 API 在**调用方上下文**失败时写(`net_socket :442/449`、`net_bind :482-538`、`net_sendto/net_recvfrom`、`net_getsockname :1953-1964`),**成功不写** → stale 滞留(`:1609` 文档化)。读端:`ui_net_sink.c:460`(uiTask 100Hz,BelowNormal 被抢占窗口最大)、`test/net_test_task.c:230/381`
|
||||
@@ -394,7 +398,7 @@ E-60"write_enable WRTC2 与手册矛盾"经三方复核(手册表头 D7~D0 顺
|
||||
|
||||
| # | 项 | 内容 |
|
||||
|---|---|---|
|
||||
| 1 | **E-02+E-06+E-20+E-21** | 阻塞模型改造:lftpd 控制通道/timeSync 改 `DONTWAIT` + 调用方状态机(ui_sink 模式推广);`net_process_messages` 长阻塞间隙按 tick 继续排空队列;`accept_timeout` 墙钟计时 + 去跨任务 state 直读 |
|
||||
| 1 | **E-02+E-06+E-20+E-21** | 阻塞模型改造:lftpd 控制通道/timeSync 改 `DONTWAIT` + 调用方状态机(ui_sink 模式推广);`net_process_messages` 长阻塞间隙按 tick 继续排空队列;`accept_timeout` 墙钟计时 + 去跨任务 state 直读。**E-02 部分已闭环(2026-09-22,f8d6e90+4a1605b)**:两触发源改 `net_recv_to` 分片有界读(落地方案 = 有界阻塞片,非 DONTWAIT 重投),台架 A/B 实证;E-06/E-20/E-21 部分仍待办 |
|
||||
| 2 | **E-05** | `net_socket/net_bind/net_getsockname` 并入队列(新消息类型);过渡方案:alloc+init 临界区 + `s_dynamic_port` 收归 netTask |
|
||||
| 3 | **E-10/E-42/E-53/E-54** | GD5F 驱动错误通道统一:init 重试 1~2 次;`wait_busy`/轮询路径 HAL 检查;ECC 使能回读校验;错误向上传递 |
|
||||
| 4 | **E-22** | lftpd/timeSync 向 ui_sink close 规则看齐(EOF 不 close、auto_relisten 常驻、仅代次变化/判死时重建) |
|
||||
@@ -525,4 +529,4 @@ E-60"write_enable WRTC2 与手册矛盾"经三方复核(手册表头 D7~D0 顺
|
||||
|
||||
---
|
||||
|
||||
*报告完。59 项发现全部带 file:line 落点;P0/P1 核心机制经父审计组逐行复核(含 `docs/芯片手册/SD2506API-G.md` L392-398/L537/§4.8 原文核对与 `SD2506_Trap_Records.md` 硬件观测交叉验证)。2026-09-21 复核修订:E-32 由 P0 降 P2(充电器 P0 链被"出厂 82H"证伪)、E-39 机制改写(ARST 在 CTR3、驱动从未写过 CTR3)、E-60"write_enable WRTC2 与手册矛盾"经手册表头位序 + DFRobot GravityRtc 官方库/社区代码 + 实测三方复核证伪(0x84 本已含 D2=WRTC2,代码与手册 L392 一致)移除,见 §7-19;18H 寄存器事实经手册 §4.8 专用表复核(Bit7=EN_Charge、Bit1=Charge1、Bit0=Charge0,复位 0x03,出厂 0x82=EN+5k,总表 L119 该行转录有误以 §4.8 为准);§6 交叉引用补 P2-2/P2-6。审计期间未修改任何代码、未执行构建;2026-09-21 依第一档 #1 完成 E-32 修复(commit 41e111b:18H 回读校验 + 漂移时写允许窗口重置与回读验证、0FH 死写与误注移除、充电宏位订正;构建 0 错误 0 警告,台架 RTC 套件 Phase 1 6/6 + Phase 2 累计 17/17 PASS 含 set==readback,产品固件重烧后启动校验 PASS,ST-LINK 全片回读 No difference);同日依第一档 #2 完成 E-31 修复(commit da1a6e8:journal.c 三处错误源治理——扫描读失败不再覆盖为 TOO_BAD、读成功但 checkpoint 不符判 CORRUPT_MAP + nand_ftl.c 错误分类——仅真空白判 fresh、其余失败返回 STA_NOINIT 给 mount 层 + freertos.c 启动块重构为 storage_bring_up() 并加 3×2s 有界重试自愈策略;构建 0 错误 0 警告;产品固件台架回归 PASS:`@test` 闭环 Required(含 `Map resumed`/`FATFS mounted`)全中、Forbidden 零命中,既有卷 2441/96064 扇区 resume 成功、用户配置 523B 原样加载、FTP 屏障链通,ST-LINK 全片回读 No difference);2026-09-22 依第一档 #3 完成 E-01 修复(commit d030cb0:poll 超长判定基于 `cfg_store_stat` 真实 st.size 前置到 `s_load_file` 之前根治死码、超长走工厂默认+重建模板+自检留痕且不触发段回调保留在线修复通道、save 输出上限 CFG_OUT_MAX→CFG_FILE_MAX_LEN、`s_write_doc` 写盘唯一闸口硬拒超长、load/poll 超长处置补 SYSLOG_SELFTEST 留痕;构建 0 错误 0 警告;台架验证 PASS:FTP STOR 5047B → poll 守卫 4s 内触发并重建 523B 工厂模板(RETR 实测)、设备保持在线、重启 load 守卫同链自愈、再重启零 `[ERR]` 无销毁循环、selftest.log 双留痕、模拟器 cfgtest 两个新回归锁场景 PASS、@test 默认闭环 PASS、ST-LINK 全片回读 No difference;验证中暴露并修复关联缺陷 `cfg_store_write_atomic` f_rename 对已存在目标不覆盖致设备端一切覆盖写静默失败(commit 70f1cc8:rename 前先 unlink 目标),详见 E-01 明细"关联新发现")。*
|
||||
*报告完。59 项发现全部带 file:line 落点;P0/P1 核心机制经父审计组逐行复核(含 `docs/芯片手册/SD2506API-G.md` L392-398/L537/§4.8 原文核对与 `SD2506_Trap_Records.md` 硬件观测交叉验证)。2026-09-21 复核修订:E-32 由 P0 降 P2(充电器 P0 链被"出厂 82H"证伪)、E-39 机制改写(ARST 在 CTR3、驱动从未写过 CTR3)、E-60"write_enable WRTC2 与手册矛盾"经手册表头位序 + DFRobot GravityRtc 官方库/社区代码 + 实测三方复核证伪(0x84 本已含 D2=WRTC2,代码与手册 L392 一致)移除,见 §7-19;18H 寄存器事实经手册 §4.8 专用表复核(Bit7=EN_Charge、Bit1=Charge1、Bit0=Charge0,复位 0x03,出厂 0x82=EN+5k,总表 L119 该行转录有误以 §4.8 为准);§6 交叉引用补 P2-2/P2-6。审计期间未修改任何代码、未执行构建;2026-09-21 依第一档 #1 完成 E-32 修复(commit 41e111b:18H 回读校验 + 漂移时写允许窗口重置与回读验证、0FH 死写与误注移除、充电宏位订正;构建 0 错误 0 警告,台架 RTC 套件 Phase 1 6/6 + Phase 2 累计 17/17 PASS 含 set==readback,产品固件重烧后启动校验 PASS,ST-LINK 全片回读 No difference);同日依第一档 #2 完成 E-31 修复(commit da1a6e8:journal.c 三处错误源治理——扫描读失败不再覆盖为 TOO_BAD、读成功但 checkpoint 不符判 CORRUPT_MAP + nand_ftl.c 错误分类——仅真空白判 fresh、其余失败返回 STA_NOINIT 给 mount 层 + freertos.c 启动块重构为 storage_bring_up() 并加 3×2s 有界重试自愈策略;构建 0 错误 0 警告;产品固件台架回归 PASS:`@test` 闭环 Required(含 `Map resumed`/`FATFS mounted`)全中、Forbidden 零命中,既有卷 2441/96064 扇区 resume 成功、用户配置 523B 原样加载、FTP 屏障链通,ST-LINK 全片回读 No difference);2026-09-22 依第一档 #3 完成 E-01 修复(commit d030cb0:poll 超长判定基于 `cfg_store_stat` 真实 st.size 前置到 `s_load_file` 之前根治死码、超长走工厂默认+重建模板+自检留痕且不触发段回调保留在线修复通道、save 输出上限 CFG_OUT_MAX→CFG_FILE_MAX_LEN、`s_write_doc` 写盘唯一闸口硬拒超长、load/poll 超长处置补 SYSLOG_SELFTEST 留痕;构建 0 错误 0 警告;台架验证 PASS:FTP STOR 5047B → poll 守卫 4s 内触发并重建 523B 工厂模板(RETR 实测)、设备保持在线、重启 load 守卫同链自愈、再重启零 `[ERR]` 无销毁循环、selftest.log 双留痕、模拟器 cfgtest 两个新回归锁场景 PASS、@test 默认闭环 PASS、ST-LINK 全片回读 No difference;验证中暴露并修复关联缺陷 `cfg_store_write_atomic` f_rename 对已存在目标不覆盖致设备端一切覆盖写静默失败(commit 70f1cc8:rename 前先 unlink 目标),详见 E-01 明细"关联新发现");2026-09-22 依第二档 #1 完成 E-02 修复(commit f8d6e90:lftpd 侧 `net_recv_to` 5ms 分片有界读 + 30s 总预算,M3 压力档 17.7s 尖峰归零;commit 4a1605b:timeSync 侧同模式改造 + 超时留痕;产品构建 `@test` 闭环 PASS;台架 A/B(`test/e02_probe.py`):挂起对时客户端下 FTP banner 旧 28554ms → 新 109ms/75ms、30s 预算拆连留痕、监听恢复行为同构、正常对时路径全通;详见 E-02 明细"已修复")。*
|
||||
|
||||
Reference in New Issue
Block a user