Rust in Everything
基于 bytes 1.12.1

常见坑

每一章对着一个报错或一个现象:先用最小的程序把它复现出来(输出是 M2 Max、rustc 1.99.0 上的原文),再到源码里找它从哪一行来,最后给出修法和检查办法。机制在前面几部分讲过的,这里只链过去,不再重复。

  1. 一个小切片让整块缓冲一直不释放:切片和原缓冲共享同一块分配;在 hyper 里把 1000 个 32 字节的请求头值存进长期容器,留住约 8 MiB 读缓冲,copy_from_slice 后只剩 32 000 字节;split 的时机决定留住哪一块;1.12.1 的 clear() 不放手。
  2. range end out of bounds 与 split_to out of bounds:slice、split_to、split_off、extend_from_within 越界的原文和出处;panic 报在 bytes.rs / bytes_mut.rs 而不是调用行,因为只有 range 标了 #[track_caller];怎么用回溯找到自己那一行,怎么不 panic 地切。
  3. index out of bounds: the len is 0 but the index is 0:with_capacity 只给容量;按下标写 panic,read(&mut buf) 返回 Ok(0) 像 EOF,split_off 能切进没写的容量;用 put_*、resize、zeroed、read_buf。
  4. advance out of bounds: the len is 3 but advancing by 4:get_* 在半包上 panic;直接在缓冲上 try_get_u32 会读走长度、让整条流错位;先在副本上 peek,整帧到齐再消费。
  5. try_get_int 把 -1 读成 16777215:1.10.0 到 1.12.1 的 try_get_int / _le / _ne 不做符号扩展;修复 #839 已合进 master 未发版;替代写法和一条升级后会变绿的测试。
  6. reserve 之后,备用容量里写的字节变了:往备用容量里写了、还没 set_len 就 reserve,这些字节不会被保留;有切片活着时 reserve 只按需分配、不翻倍;with_capacity(0) 出生的缓冲原始容量是 0。
  7. remaining() 是 25,chunk() 只有 8 个字节:把 chunk() 当成全部数据的解析器,在 Chain 这类不连续的 Buf 上找不到分隔符或切定长字段时 panic。
  8. try_into_mut 返回 Err:还有别的句柄;或者存储是 from_static / from_owner,永远是 Err。
  9. unsplit 之后前后两段对调了:顺序反了不报错,内容被静默拷贝追加;split_off 越过长度后 unsplit 丢容量;try_unsplit 返回 Ok 不代表来自同一块缓冲。
flowchart TB
  q{碰到了什么}
  q -->|内存只涨不降| p1["1 小切片留缓冲"]
  q -->|"out of bounds panic"| pp{哪一种}
  pp -->|"slice / split"| p2["2 越界"]
  pp -->|"the len is 0"| p3["3 容量不是长度"]
  pp -->|"advance out of bounds"| p4["4 半包"]
  q -->|数值不对| p5["5 try_get_int"]
  q -->|"BytesMut 行为意外"| bm["6 reserve 或 9 unsplit"]
  q -->|"Chain 解析出错"| p7["7 Chain"]
  q -->|"转不回 BytesMut"| p8["8 try_into_mut"]

💬 关联讨论

发起讨论
加载中...