fix(NET,lftpd): 处置覆盖率照出的三处死路径(改名 + 修 timeout=0 + 激活异常集)
三处都由本轮 P1 新增的主机单测照出,用户逐条裁定后实施。共同性质:都不是改动引入
的回归,而是**从没被执行到的分支**——生产路径上要么没有调用者、要么没走边界,所以
编译器(0 错 0 警)、cppcheck、真机日志对它都无话可说。
1) 缺陷一(选 a:改名,行为零变化)
lftpd_string_trim 的尾部循环起点落在 strlen(p) 那一格 NUL,isspace(0) 为假 →
循环体一次都不执行,"尾部空白从未被裁",而名字承诺两头都去。改名
lftpd_string_ltrim + 删掉那条死循环 + 在 .h/.c 写明"只去前导"。不去尾才是对的:
RFC 959 以命令终止符 CRLF 界定命令,参数(PASS 口令、含空格的文件名)的尾随
空格属于参数本体,去掉等于静默改数据;CRLF 已由 lftpd_inet_read_line 截断。
调用点 lftpd.c 同步改名。全库无遗留真引用(余 6 处旧名均为解释改名历史的散文)。
2) 缺陷二(按推荐修)
net_select 的 timeout = {0,0} 换算出 timeout_ms = 0,而退出条件写着
if ((timeout_ms > 0) && (已用时 >= timeout_ms)) → 超时永不生效,退化成死等;
POSIX 语义是"只查一轮立即返回"。去掉 timeout_ms > 0 这个错误前置即可。就绪
检查在本判断之前,故有就绪时仍立刻带计数返回;同文件 net_poll_events 的
timeout >= 0 本来就对,现在两条对齐。风险面:拿它当"非阻塞查一遍"会让 netTask
回不到主循环,而 netTask 在 IWDG required_mask 里(串行 socket 栈唯一执行者)。
3) 缺陷三(选 ①:按 POSIX 置位)
exceptfds 是恒为空的死参数:循环开头 p_sock == NULL → continue 先跳过,而
check_socket_error() 只有"表项为空 / fd 越界"才返回 1,越界的 i 又不在本循环
范围内 → 调用方按 POSIX 直觉用它收异常,永远什么都收不到,且返回码不报错。
把异常判定提到 continue 之前:表项不存在的 fd 计入 exceptfds 与返回计数,并更新
函数注释。选 ① 会改变返回计数语义,故补一条"未请求异常集时不计数"的用例,
确保只查可读的老调用方不被误伤(TC-NETSEL-012b)。
测试同步翻转:原 TC-NETSEL-008 / TC-NETSEL-012 是"现状桩、改了会响",现在改成正向
契约,并新增 TC-NETSEL-012c(异常位只落到被请求的那个集合);TC-LFTSTR-005 从
"尾部不裁"的现状登记改为正向契约(尾随空格必须保留)。net_select 22/22、
lftpd_io 33/33 全绿。
@build:0 错误 0 警告。实测体积 ER_IROM1 232,512 B(快照 232,536 → **−24 B**)、
Flash 233,704 B(−20 B)、RW_IRAM1 75,272 B(+8 B 是上一提交 net_cfg 那个字节,
本批零新增)、**RW_CCM 57,376 B 不变**;四档百分比 22.2/57.4/87.9/22.3 全不变。
Code 减少 36 B 即删掉的死循环。
覆盖率台账:门禁如实报了一次 lftpd_string.c 已覆盖行 8 → 7(**代码少了一行**,不是
覆盖退化),已 --update-baseline 重登;现 22/22 套件、line=3003/3446(87.1%)、
func=236/259(91.1%)、tested_files=26、untested_files=118。
文档:主机单测覆盖率口径 §9 新增"三处死路径的处置"小节(裁定、改法、影响、钉住
它的用例一一对应),并把两处"等裁定"的登记改为已处置。
自查:coding-standard / test-cppcheck / id-check --strict(无台账外新账)/ doc-links
(35 处 = 存量)全过;八个改动文件与 HEAD 逐项比对 BOM/CR/U+FFFD/行尾无变化
(这几个文件本就不带 BOM,未被动过)。pre-commit --all-files 仍只有三条失败且与
本分支无关:mem-numbers / mem-budget(.map 与 docs/内存管理 受管快照漂移,增量见
上,按并行分支约定不在分支里 --write,等 Lead 合并后统一回填)与 ui-golden
(simulator/tests/ref/*.bin 在 .gitignore 内,新建 worktree 天生没有黄金参考)。
This commit is contained in:
+34
-1
@@ -249,13 +249,46 @@
|
||||
⚠ 总体 `line_rate` 88.2% → **87.2%**:**这正是 §5 说的摊薄,不是回退**——`lftpd_io.c` 只测了
|
||||
一半就进分母,分母涨得比分子快;要盯的是 `files_tested`/`files_untested` 两个数。
|
||||
|
||||
本批又照出一处(**语义未改,等裁定**):`lftpd_string_trim` 的尾部循环写成
|
||||
**(同日已处置,见下方"三处死路径的处置")**原照出处:`lftpd_string_trim` 的尾部循环写成
|
||||
`for (i = strlen(p); i >= 0 && isspace(p[i]); i--)`,i 起步那格是 `'\0'`、`isspace(0)` 为假 →
|
||||
循环一次都不执行,**尾部空白/CRLF 从未被裁掉**。今天不发作是因为 CRLF 在
|
||||
`lftpd_inet_read_line` 里已用 `strstr("\r\n")` 截断、唯一调用点 `lftpd.c` 只用返回指针去行首;
|
||||
风险在"以后有人拿它去尾部空白"。修它一行即可,但会改变 FTP 参数(含空格的文件名/
|
||||
口令)的可见行为,需与 FTP 域一起过 → 现在只用 TC-LFTSTR-005 把现状钉成"改了会响"。
|
||||
|
||||
### 三处死路径的处置(2026-10-23,用户逐条裁定后实施)
|
||||
|
||||
三处都不是改动引入的回归,而是**从没被执行到的分支**:生产路径上要么没有调用者、
|
||||
要么调用者没走边界,所以编译器(0 错 0 警)、`cppcheck`、真机日志对它都无话可说。
|
||||
覆盖率把"进没进过"变成可见数字之后,我为了写用例逐行读了它们的判定条件才撞见。
|
||||
|
||||
| 缺陷 | 裁定 | 改法与影响 | 现在钉住它的用例 |
|
||||
|---|---|---|---|
|
||||
| `lftpd_string_trim` 尾部循环起点落在 NUL,`isspace(0)` 为假 → **尾部从不被裁**
|
||||
(名字却承诺两头都去) | **选 (a) 改名** | 改名 `lftpd_string_ltrim` + 删掉那条死循环 +
|
||||
在 `.h`/`.c` 写明"只去前导"。**行为零变化**(那条循环本来就不执行);不去尾才是对的:
|
||||
RFC 959 以 CRLF 界定命令,参数(`PASS` 口令、含空格文件名)的尾随空格属于参数本体,
|
||||
去掉等于静默改数据。`lftpd.c` 调用点同步改名 | TC-LFTSTR-001..005(005 现在是正向契约:
|
||||
尾随空格必须保留) |
|
||||
| `net_select` 的 `timeout = {0,0}` 换算出 `timeout_ms = 0`,而退出条件写着
|
||||
`if ((timeout_ms > 0) && (已用时 >= timeout_ms)))` → **超时永不生效**,退化成死等
|
||||
(POSIX 是"只查一轮立即返回") | **按推荐修** | 去掉 `timeout_ms > 0` 这个错误前置,
|
||||
变成 `if (已用时 >= timeout_ms) break;`。就绪检查在它之前,故有就绪时仍立刻带计数返回;
|
||||
同文件 `net_poll_events` 的 `timeout >= 0` 本来就是对的,现在两条对齐。风险面:
|
||||
拿它当"非阻塞查一遍"会让 netTask 回不到主循环,而 netTask 在 IWDG `required_mask` 里 |
|
||||
TC-NETSEL-008(已翻成正向断言:`rc==0` 且一轮都不睡) |
|
||||
| `exceptfds` 是恒为空的死参数:循环开头 `p_sock == NULL → continue` 先跳过,而
|
||||
`check_socket_error` 只有"表项为空/越界"才为真,越界的 `i` 又不在循环范围内 |
|
||||
**选 ①**(按 POSIX 置位) | 把异常判定提到 `continue` **之前**:表项不存在的 fd 计入
|
||||
`exceptfds` 并计入返回计数;同时更新函数注释。选 ① 会改变返回计数语义(缺失 fd 现在
|
||||
算就绪),因此补一条"未请求异常集时不计数"的用例,确保只查可读的老调用方不被误伤 |
|
||||
TC-NETSEL-012 / 012b / 012c(新增) |
|
||||
|
||||
**处置后的账**:`@build` 0 错误 0 警告,`Code` **−36 B**(删掉的死循环),
|
||||
`RW-data`/`ZI-data` 不变 → **RAM 零变化**。`lftpd_string.c` 的已覆盖行 8 → 7
|
||||
被门禁判了一次 `REGRESS`——那是台账在如实反映"代码少了一行",不是覆盖退化,
|
||||
已按 `--update-baseline` 重登(这条恰好反证门禁有效:删代码想悄悄过去,它会拦)。
|
||||
两处"现状桩"翻成正向契约,另新增 `TC-NETSEL-012c`;全量 22 套件仍然全绿。
|
||||
### P2|值得但工程量大(5 个 `.c` = 2,226 行)
|
||||
|
||||
1. **`net_socket.c`(1,251 行 / 51 个函数,全仓最大的逻辑块)** —— 必须**分片**,别一次吞。
|
||||
|
||||
Reference in New Issue
Block a user