一个不稳定的测试揪出 Redis 内存漏洞
A flaky test exposed a Redis client use-after-free

作为一个持续集成平台,Buildkite 对 flaky tests 再熟悉不过了。但这次,David 发现的一组不稳定测试背后,竟藏着一个致命的 Redis use-after-free 内存错误。从最初的误判为竞态条件,到 Patrick 捕获到诡异的 Double free 报错,再到 Rian 利用 core dump 和 ASAN 工具精准定位到 hiredis 库中的线程竞争问题,这场历时数天的调试之旅堪称技术侦探小说。最终,团队不仅修复了漏洞,还向上游提交了复现案例。这个故事生动展示了工具链、团队协作与一点点运气如何合力攻克最棘手的内存安全难题。
修复一个确定性发生的 bug 已经很难了,而要复现触发它的特定场景往往是最难的一步。
HN 评论区
14- toast0
更难的还是当 bug 的成因发生在其表现之前。
我还没调试过那种表现先于成因出现的 bug……听起来更难。:p
- StilesCrisis
大段大段冗长铺垫,最后来一句“一位同事开启了 ASAN 并报告了一个 bug [链接]”,却没有任何解释。令人失望。
- serious_angel
非常感谢!这是一篇很棒的文章!不过,文中并没有提及具体的排查步骤,包括:
> 由此,他确认该异常是由调用 C 函数 memmove 触发的。虽然这次调用的源地址和目的地址看起来正常,但 size 字段却被设置为……
我大致能理解文中提到的这些内容,但如果能了解更多关于他究竟是如何发现问题的细节,以及使用了什么工具集,那就太棒了。是用的 gdb、Valgrind、JetBrains、IDA Pro,还是其他某种通用或复杂的 dump 查看器/工具集?
另外,网站顶部的交互式奇迹效果真是令人惊叹……这让我想起了 Yusuke Endoh 关于流体模拟算法的文章!向开发者、这位实现它的艺术家致以诚挚的谢意!
显然,在幕后,流体颜色存储在一个数组中,每种颜色都有明确的含义!
// 按 STACK 顺序排列的类别:索引 0 在底部 → 4 在表面
const CATS = [
{ key: "Code", rgb: [133, 232, 157] },
{ key: "Craft", rgb: [179, 146, 240] },
{ key: "Lessons", rgb: [249, 117, 131] },
{ key: "Story", rgb: [255, 171, 112] },
{ key: "Opinion", rgb: [158, 203, 255] },
];