Buffer indexOf 返回负偏移
大 Buffer 在高于 2 GiB 的命中位置可能返回溢出的负数,导致游标回退。核对 Node 26.11.1 修正与受控高偏移验收。
扫描大型 Buffer 时,indexOf() 找到了目标,却返回一个小于 -1 的负数。接下来游标回退、重复解析,甚至越读越多。先检查实际命中位置是否达到 2 ** 31,以及所用 Node 的 Buffer 搜索返回值实现。
已确认的环境包含 Node 26.10.0、24.21.0 的 Windows 构建和 22.22.2 的 Linux 构建。正式版 26.11.1 的对应返回路径使用了 64 位整数。本文不把这些观察扩大成所有历史版本都受影响,也不指定每个发行线的首个修复补丁。
未找到应该是 -1
Buffer.indexOf() 返回第一次命中的位置,未命中才返回 -1。旧实现把高位命中偏移转换为有符号 32 位整数时,达到 2 ** 31 的位置可能溢出为负数。
这不是搜索没找到目标。若业务把结果直接加一作为下次起点,或者只用 position === -1 结束扫描,负偏移便可能把游标带回前面,制造重复处理或循环。
字符串、Buffer 和单字节数字形式的搜索都需要按实际调用核对。只在小 Buffer 上测试通过,无法覆盖高偏移返回;同时,大 Buffer 本身也不是充分条件,关键是命中的位置达到这个边界。
先阻止异常结果驱动游标
排查时保留搜索方法、起点、Buffer 长度和返回位置。无需公开 Buffer 内容,也不必在业务机器额外分配数 GB 数据来复制症状。
如果已有扫描代码拿到了明显异常的返回值,应停止这次扫描并明确报告,避免继续驱动游标。下面只展示判断位置,data、needle 和 cursor 由原应用的受控输入提供:
const position = data.indexOf(needle, cursor);
if (position < -1) {
throw new Error('Invalid Buffer search offset');
}
这是一道异常保护,不是修复搜索算法。它不能证明其他负值都没有问题,也没有包含完整的游标推进和跨块匹配实现。
不要直接把所有负数当成“结束”,否则会静默截掉尚未处理的数据;也不要统一转成无符号值后继续运行,这会把真正的 -1 变成另一个大数,并把应用绑定到某个旧实现的溢出细节。
选择包含高偏移修正的版本
已核对的 26.11.1 正式源码修正了对应搜索结果的整数返回路径。项目可沿兼容版本选择含有修复的发行包,再确认服务、worker 或桌面宿主实际使用的 Node,而不是只看终端中的版本。
如果必须改用分块处理,需要保留绝对偏移、跨块匹配和游标单调前进的约定。分隔符可能跨越块边界,搜索也可能接受字符串或多字节序列;简单对每块分别搜索再拼结果,不能当成通用替代算法。
不同版本支持的搜索参数也应保持清楚。后续 API 新增的参数,不能直接复制给旧运行时以为它们具有相同限制效果。
验收已知位置与未命中
在资源受控的验收环境中,对已知高位目标确认返回准确的非负位置,再检查未命中仍为 -1、普通低位命中没有回归。业务扫描应持续前进,不重复处理先前范围。
如果调整为分块,还要覆盖块边界附近的目标。修正一个整数返回问题,与证明整套解析流程没有重复或漏读,是两层验收,不能只凭不再内存溢出就合并判断。


