已关闭
[Bug]: IndexedDataset readers leak mmap resources and may return invalid or corrupted data #376
rongyue创建于 27 天前关闭于 21 天前
26 天前 关联了pull request:test_mem_warning
26 天前 删除了关联的pull request:test_mem_warning
26 天前 关联了pull request:test_mem_warning
21 天前 issue状态由 TODO 改变为 CLOSED
21 天前 关闭了 issue
Checklist
🐛 Describe the bug
IndexedDataset 的本地 indexed data reader 存在多处资源生命周期和边界读取问题,可能导致 mmap 资源泄漏、返回数组引用已释放 mmap、短读时返回未初始化数据,以及大 slice 场景下 token count 溢出。
涉及文件:
hyper_parallel/data/indexed/io.py
问题包括:
_IndexReader.del 强制关闭 mmap,但实例仍持有由 numpy.frombuffer(self._buffer, ...) 创建的 sequence_lengths、sequence_pointers、document_indices、sequence_modes 等 exported buffer view。析构时 mmap.close() 可能抛 BufferError,导致 mmap 未正常释放。IndexedDatasetBuilder.add_index 合并多个 index 分片时会反复创建并释放 _IndexReader,容易触发该路径。
_IndexReader.getitem 使用 @lru_cache(maxsize=8) 装饰实例方法。该 cache 挂在类级函数对象上,key 包含 self,因此最近 8 个 _IndexReader 实例会被强引用保留,连带整份 .idx mmap 常驻内存。多源 blend 或重复构建 Dataset 时会累积占用。
_MMapBinReader.read() 返回 numpy.frombuffer(self._buffer, ...) 的零拷贝 view,但 _MMapBinReader.del 会强制关闭底层 mmap。如果上层仍持有 IndexedDataset.get()/getitem 返回的数组,而 reader 被释放,返回数组可能引用已 munmap 的地址,存在 SIGSEGV 风险。
_FileBinReader.read() 使用 numpy.empty(count, dtype=dtype) 预分配输出,然后 f.readinto(out),但没有检查 readinto 返回值。若 .bin 被截断、idx/bin 不匹配,或请求范围越过 .bin 文件末尾,readinto 只会填充部分字节,数组尾部保留未初始化内存,并被静默当作 token id 返回,造成数据损坏。
IndexedDataset.getitem 的 slice 分支对 int32 sequence_lengths 使用 accumulate/sum 累加。对于覆盖超过 2^31 token 的连续 slice,numpy int32 累加可能溢出,导致传给 bin_reader.read() 的 count 错误,进一步造成截断读取、错位 split,甚至异常的大范围读取。
Expected behavior
IndexedDataset reader 应满足以下行为:
Additional context
建议修复方向:
Environment info
Repository: mindspore/hyper-parallel
Component: hyper_parallel/data/indexed/io.py
Affected classes:
Observed on current development branch around indexed dataset offline preprocessing changes.
Thanks for contributing 🎉!