🔴 [H2] mmap 与索引构建之间存在 TOCTOU 竞态 #2
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
文件:
core/io/file_reader.rs:23-42分类: 并发安全
问题:
FileReader::open()先 mmap 文件,再通过 BufReader 读取文件构建行索引。如果文件在两步之间被修改,line_index描述的字节范围可能与mmap数据不一致。影响:
get_line()可能返回错误行或 panic。建议修复: 从 mmap 字节直接构建索引,确保数据和索引来自同一快照。
修复方案
根因:
FileReader::open()和reload()中,mmap 映射(快照 A)和LineIndex::from_reader(BufReader)(快照 B)是两个独立的文件读取操作。如果文件在两步之间被外部修改,索引偏移量与 mmap 字节数据不一致,导致get_line()返回错误内容或越界 panic。修复: 将
LineIndex::from_reader(BufReader<&File>)替换为LineIndex::from_bytes(&mmap),让行索引直接从 mmap 内存快照构建,确保数据和索引来自同一个不可变的快照。变更文件:
crates/core/src/io/file_reader.rsopen():from_reader→from_bytes(&mmap)reload():from_reader→from_bytes(&mmap)update_for_append(): 无需改动(已从 mmap 切片构建)新增测试 (4 个):
test_open_from_bytes_matches_from_reader: 验证 from_bytes 与 from_reader 产出完全一致的索引(空文件/单行/跨块 256/300/512 行)test_reload_after_external_modify_returns_correct_content: 外部覆盖文件后 reload 返回新内容test_reload_after_truncate_then_rewrite_no_stale_data: 截断后写入更短内容,旧行不可访问test_open_reload_idempotent_cross_block: 600 行跨块场景 open 与 reload 逐行一致提交:
24fe97a