诊断 Rust 无界通道中的双重释放并发错误

主要观点:Materialize 近期在 Rust 的 crossbeam 及标准库的无界通道中发现并发 bug,会导致双释放和未定义行为,此问题存在一年多未被发现,Rust 1.87.0 已包含修复,文中详述调试过程、竞争条件及内部不变量等。
关键信息

  • 2 月 26 日 CI 间歇性失败,错误为内存损坏,用 AddressSanitizer 发现问题与 2 月 7 日更新的 crossbeam-channel 有关。
  • 分析无界通道结构,初始化时通道为半初始化状态,这是重现竞争条件的关键。
  • 竞争条件分析得出特定条件下会出现双释放,如线程调度顺序等。
  • 影响评估确定受影响的 crossbeam 和 Rust std 通道版本。
  • 快速准备 PR 修复问题,两个社区反应迅速,Tor 社区发布安全咨询。
    重要细节
  • crossbeam 提供多种通道类型,无界通道内部由链表实现,通过 Sender<T>Receiver<T> 操作。
  • disconnect_receivers 函数在最后接收者丢弃时调用,Channel::drop 函数在最后引用丢弃时执行类似逻辑。
  • 代码中部分修改导致引入双释放问题,如 2023 年 4 月和 2024 年 2 月的 PR 变更。
  • 修复后 crossbeam 快速发布新版本并从 crates.io 移除受影响版本,Rust 侧也合并修复并提名回溯到 1.87.0 版本。
  • 强调即使在 Rust 中,unsafe 代码和宽松原子操作仍可能导致错误,需重视 CI、诊断工具和对抗性压力测试等。
阅读 9
0 条评论