## 位置 - `bufiox/tail.go:56`(`maxLines := int64(budget) * tailMaxLineFactor`) - `bufiox/tail.go:68`(丢头循环条件 `int64(len(lines)) > maxLines`) ## 现状 实现处自带注释(`bufiox/tail.go:56`): ```go maxLines := int64(budget) * tailMaxLineFactor // int64:budget 极大时乘法不回绕 ``` `TailLines` 的 godoc(`bufiox/tail.go:40-48`): ```go // - 超预算从**头部按行丢弃**:窗口内保留行的内容字节总数 <= budget // (分隔符不计入),且行数 <= budget×4(软上限,防极小行无限堆积); ``` ## 问题 `budget` 是 `int`;`int64(budget) * tailMaxLineFactor`(`tailMaxLineFactor = 4`) 在 `budget > 2^61` 时 **int64 乘法回绕**。 注释宣称的「int64:budget 极大时乘法不回绕」与实现**相反**—— 转成 int64 只避免了 int 的回绕,int64 自身的乘法一样会回绕。 回绕后的 `maxLines` 为负或 0 ⇒ `bufiox/tail.go:68` 的丢头循环条件 `int64(len(lines)) > maxLines` 恒真 ⇒ **只保留最后一行**。 ⇒ godoc 承诺的「行数 <= budget×4」在 budget 极大时退化为「行数 <= 1」。 ## 证据 ```go for _, budget := range []int{1024, 1048576, 1 << 61, 1 << 62, math.MaxInt64} { tail, truncated, err := bufiox.TailLines(strings.NewReader(strings.Repeat("\n", 100)), budget) // 统计 tail 的行数 } ``` 实测输出原文: ``` [TailLines] budget=1024 保留行数=100 truncated=false err=<nil> (输入共 100 行,期望保留 100 行) [TailLines] budget=1048576 保留行数=100 truncated=false err=<nil> (输入共 100 行,期望保留 100 行) [TailLines] budget=2305843009213693952 保留行数=1 truncated=true err=<nil> (输入共 100 行,期望保留 100 行) [TailLines] budget=4611686018427387904 保留行数=1 truncated=true err=<nil> (输入共 100 行,期望保留 100 行) [TailLines] budget=9223372036854775807 保留行数=1 truncated=true err=<nil> (输入共 100 行,期望保留 100 行) --- PASS: TestProbe_TailLines_LineBudgetOverflow (0.00s) ``` ## 对照组 - `budget=1024` / `budget=1MB`:保留全部 100 行、`truncated=false` ✓ 正常路径无恙。 - `budget >= 2^61`:**只保留 1 行**,且 `truncated=true`。 ## 影响 `TailLines` 的用途是「给 LLM 做 CI 失败日志尾部归因」。 预算极大时本应「几乎全量保留」,实际只剩最后一行 ⇒ 归因提示里只剩一行日志, 且 `truncated=true` 反而让调用方以为「只是头部被省略」——**失败形态被伪装成了正常截断**。 触发需要 2^61 字节级的预算(现实中不会走到),但**注释里那句「int64:budget 极大时乘法不回绕」本身是错的**, 会把后来的维护者引向错误的安全感(正是这类注释存在的原因才要修)。 ## 建议修复 在乘法前判上界(或做饱和乘法),与本仓 `pagination` 的既有做法一致—— `pagination/page.go:44-52` 的注释明写「**乘法前**判,而不是乘法后看结果是否为负」, 且 `CHANGELOG.md` 有专门的修复记录(「修复(pagination):偏移量溢出保护只兜住一半情形 ⇒ 返回垃圾偏移量」)。 ```go maxLines := int64(math.MaxInt64 / tailMaxLineFactor) if int64(budget) < maxLines { maxLines = int64(budget) * tailMaxLineFactor } ``` (或者用 `math/bits` 做饱和乘法。) 同时把那句注释改成实际成立的表述,例如: `// 乘法前判上界:budget 极大时饱和到 MaxInt64,避免 int64 乘法回绕`。 ## 版本 - `github.com/oekit/pkg` HEAD `4e32ee8`
Activity
Merge pull request #421 from oekit/sweep/20261112-l1
zy84338719 commentedon Nov 12, 2026
已合入修复 ✅(无 SemVer 发布:本次改动不发版本)
变更内容
TailLines 行数软上限乘法前判上界(同 pagination 口径),饱和 MaxInt64,修正反向注释
合入:PR #421(https://github.com/oekit/pkg/pull/421),merge commit
63917515,2026-11-12T17:10:03ZCI:
link✅ /Lint & Test / Test✅ /Lint & Test / Lint✅ /Zero Third-Party Deps✅