🟡 [M3] read_cache 零长度读取命中空缓存槽 #13

Closed
opened 2026-06-03 13:53:56 +08:00 by dailz · 1 comment
Owner

文件: core/io/read_cache.rs:76-84
分类: 缓存边界

问题: get(file, 0, 0) 会命中空的缓存槽(因为 block_offset==0, len==0),返回 Ok(&[]) 而不实际读文件。

建议修复: 特殊处理 len==0,或要求 slot.len > 0 才算命中。

**文件**: `core/io/read_cache.rs:76-84` **分类**: 缓存边界 **问题**: `get(file, 0, 0)` 会命中空的缓存槽(因为 `block_offset==0, len==0`),返回 `Ok(&[])` 而不实际读文件。 **建议修复**: 特殊处理 `len==0`,或要求 `slot.len > 0` 才算命中。
dailz added the severity/mediumarea/iobug labels 2026-06-03 13:53:56 +08:00
dailz closed this issue 2026-06-09 10:48:43 +08:00
Author
Owner

修复方案

根因

缓存命中条件 slot.block_offset == aligned_key && request_end <= slot.block_offset + slot.len 未检查 slot.len > 0,导致初始化状态的空槽(block_offset=0, len=0)被 get(file, 0, 0) 误判为命中,返回 Ok(&[]) 而跳过 read_at 和错误检查。

改动(commit d37ed6d)

改动 说明
get() 顶部加 if len == 0 { return Ok(&[]) } 零长度读为合法无操作,匹配 std::io 语义
命中条件加 slot.len > 0 空槽不再被误判命中
request_end 改用 checked_add 防止 u64::MAX 附近溢出
block_end / bytes_end 改用 saturating_add 防止 debug panic / release 回绕
修正误导注释 原注释声称的行为与命中路径不符
clear() 完全重置槽位 纵深防御,重置 block_offset 和 last_access
注册 pub mod read_cache 模块原未导出,测试无法运行

新增回归测试(4 个)

  • zero_len_read_is_noop_on_fresh_cache — 新缓存 + 空文件,get(0,0) 不触发 read_at
  • zero_len_read_is_noop_on_populated_cache — 已缓存后 get(0,0) 不改变 LRU 状态
  • zero_len_read_at_max_offset_is_ok — get(u64::MAX, 0) 不溢出
  • nonzero_read_range_overflow_returns_invalid_input — get(u64::MAX, 1) 返回 InvalidInput

测试结果

18 passed, 0 failed(14 原有 + 4 新增)

## 修复方案 ### 根因 缓存命中条件 `slot.block_offset == aligned_key && request_end <= slot.block_offset + slot.len` 未检查 `slot.len > 0`,导致初始化状态的空槽(`block_offset=0, len=0`)被 `get(file, 0, 0)` 误判为命中,返回 `Ok(&[])` 而跳过 `read_at` 和错误检查。 ### 改动(commit d37ed6d) | 改动 | 说明 | |------|------| | `get()` 顶部加 `if len == 0 { return Ok(&[]) }` | 零长度读为合法无操作,匹配 std::io 语义 | | 命中条件加 `slot.len > 0` | 空槽不再被误判命中 | | `request_end` 改用 `checked_add` | 防止 u64::MAX 附近溢出 | | `block_end` / `bytes_end` 改用 `saturating_add` | 防止 debug panic / release 回绕 | | 修正误导注释 | 原注释声称的行为与命中路径不符 | | `clear()` 完全重置槽位 | 纵深防御,重置 block_offset 和 last_access | | 注册 `pub mod read_cache` | 模块原未导出,测试无法运行 | ### 新增回归测试(4 个) - `zero_len_read_is_noop_on_fresh_cache` — 新缓存 + 空文件,get(0,0) 不触发 read_at - `zero_len_read_is_noop_on_populated_cache` — 已缓存后 get(0,0) 不改变 LRU 状态 - `zero_len_read_at_max_offset_is_ok` — get(u64::MAX, 0) 不溢出 - `nonzero_read_range_overflow_returns_invalid_input` — get(u64::MAX, 1) 返回 InvalidInput ### 测试结果 18 passed, 0 failed(14 原有 + 4 新增)
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: dailz/logViewer#13