码农高天
通过彻底弃用内置 Pickle 模块消除反序列化安全漏洞与环境依赖,确保开发者在本地缺少特定依赖包的情况下也能稳定还原并交互排查云端 CI 的崩溃现场。
AI-assisted summary of 面对无法本地复现的bug,只好尸检了! — original source. Check the original for full context.
Source published:
Key ideas
- 码农高天推出了开源事后调试(Post-Mortem Debugging)工具 coredumpy,可在自动化测试或程序崩溃瞬间抓取现场并保存为 dump 文件,帮助排查无法在本地复现的 CI 偶发性 bug。 (0:00)
- coredumpy 支持在 VS Code 插件或终端 PDB 中还原运行切片,不仅能还原各层栈帧的局部变量,还允许开发者在控制台动态执行 Python 表达式求值甚至就地修改内存变量。 (1:04)
- 该工具在底层架构上完全摒弃了 Python 内置的 pickle 序列化,彻底消除了反序列化任意数据引发的远程代码执行安全隐患,并避免了因对象不可序列化而中断保存流程的问题。 (3:32)
- 由于解耦了运行环境,开发者即便在未安装远端依赖的干净本地环境中,依然可以顺利载入并审查远端 CI 生成的 dump 文件,同时工具也支持针对复杂数据结构自定义编解码扩展。 (3:32)
Detailed notes
## Background 该视频由 YouTube 频道“码农高天”于 2025 年 3 月 15 日发布。视频简介指出,本期内容主要介绍事后调试(Post-Mortem Debugging)的概念,以及作者近期编写的 Python 事后调试工具 coredumpy,该工具能够保存测试报错发生时的程序节点,方便开发者在本地排查定位问题源头。
## TL;DR 视频从开源项目 VizTracer 在 GitHub Actions CI 中偶现断言失败、本地却无法复现的痛点切入,系统介绍了被称为“尸检”的事后调试(Post-Mortem Debugging)技术。码农高天演示了通过下载 CI 报错时生成的 coredumpy 文件,在本地 VS Code 或 PDB 中还原现场、检查调用栈与局部变量,并动态执行 Python 表达式,迅速锁定系第三方依赖库 loky 刚发布的版本引入的参数错误。最后,作者阐述了 coredumpy 的多场景接入方式,并重点解析其摒弃 Python 内置 pickle 序列化的核心设计,从而确保了安全性、容错性与跨环境解耦能力。
## Atmosphere & style 视频风格务实接地气且带有技术博主特有的风趣幽默,开篇以开发者都深有体会的 CI 诡异报错引发强烈共鸣。现场演示排查过程流畅老练,当顺藤摸瓜发现是第三方库几小时前刚发版的缺陷时,作者幽默澄清“不是我的锅”,营造出轻松愉快的调试侦探感。整体讲解既有硬核的工程剖析,又充满直击生产痛点的真实务实感。
## Bulletin - [00:00](https://www.youtube.com/watch?v=BoGsBGXQ4CA&t=0s) 码农高天推出了开源事后调试(Post-Mortem Debugging)工具 coredumpy,可在自动化测试或程序崩溃瞬间抓取现场并保存为 dump 文件,帮助排查无法在本地复现的 CI 偶发性 bug。 - [01:04](https://www.youtube.com/watch?v=BoGsBGXQ4CA&t=64s) coredumpy 支持在 VS Code 插件或终端 PDB 中还原运行切片,不仅能还原各层栈帧的局部变量,还允许开发者在控制台动态执行 Python 表达式求值甚至就地修改内存变量。 - [03:32](https://www.youtube.com/watch?v=BoGsBGXQ4CA&t=212s) 该工具在底层架构上完全摒弃了 Python 内置的 pickle 序列化,彻底消除了反序列化任意数据引发的远程代码执行安全隐患,并避免了因对象不可序列化而中断保存流程的问题。 - [03:32](https://www.youtube.com/watch?v=BoGsBGXQ4CA&t=212s) 由于解耦了运行环境,开发者即便在未安装远端依赖的干净本地环境中,依然可以顺利载入并审查远端 CI 生成的 dump 文件,同时工具也支持针对复杂数据结构自定义编解码扩展。
## Key takeaways - [00:00](https://www.youtube.com/watch?v=BoGsBGXQ4CA&t=0s) CI 自动化测试中的断言失败常因日志简略且仅在特定环境偶发出现,导致本地难以复现,排查极度困难。 - [00:00](https://www.youtube.com/watch?v=BoGsBGXQ4CA&t=0s) Post-Mortem Debugging(事后调试/尸检)技术的核心思路是从已发生的错误现场提取全量状态信息以溯源问题。 - [00:00](https://www.youtube.com/watch?v=BoGsBGXQ4CA&t=0s) 在 CI 流程中,coredumpy 可以在测试失败时截取崩溃现场上下文,并将 dump 数据文件作为构建产物上传供本地下载分析。 - [01:04](https://www.youtube.com/watch?v=BoGsBGXQ4CA&t=64s) 通过 VS Code 的 coredumpy 插件,开发者可以直观浏览完整调用栈并快速定位到报错崩溃的具体代码行。 - [01:04](https://www.youtube.com/watch?v=BoGsBGXQ4CA&t=64s) 事后调试现场保留了所有局部变量,配合 Debug Console 可以直接对未经格式化的底层数据(如 stderr bytes)执行求值并解码展示。 - [01:04](https://www.youtube.com/watch?v=BoGsBGXQ4CA&t=64s) 高天通过现场分析准确定位到了上游依赖库 loky 刚发布的 release 中传参数量不匹配的回归缺陷,证明了调试工具对外部依赖引发问题的定位效率。 - [01:04](https://www.youtube.com/watch?v=BoGsBGXQ4CA&t=64s) coredumpy 不仅提供静态视图,还支持如真机断点般的交互式求值与内存变量就地修改,同时为纯终端开发者完整兼容 PDB 调试体验。 - [03:32](https://www.youtube.com/watch?v=BoGsBGXQ4CA&t=212s) 该工具接入方式极低侵入,支持通过一行补丁代码集成 unittest、Pytest 命令行参数、独立命令启动以及关键代码分支手动保存快照。 - [03:32](https://www.youtube.com/watch?v=BoGsBGXQ4CA&t=212s) coredumpy 完全不依赖 pickle,避免了加载外部或不受信任 CI 的 dump 文件时可能引发的远程代码执行安全风险。 - [03:32](https://www.youtube.com/watch?v=BoGsBGXQ4CA&t=212s) 传统 pickle 遇到套接字或生成器等特殊对象会报错中断,而 coredumpy 具备极高容错性,能兜底保证各类复杂场景下 dump 过程不崩溃。 - [03:32](https://www.youtube.com/watch?v=BoGsBGXQ4CA&t=212s) 绕开 pickle 使 dump 文件彻底解耦本地运行环境,无需在分析机上完整还原与远端一致的依赖环境即可直接查看变量与调用栈。 - [03:32](https://www.youtube.com/watch?v=BoGsBGXQ4CA&t=212s) 针对极其复杂或奇特的数据结构,coredumpy 提供了开放的可扩展接口供用户编写自定义序列化与反序列化逻辑。
## Detailed walkthrough ### [00:00](https://www.youtube.com/watch?v=BoGsBGXQ4CA&t=0s) 无法本地复现的 CI 报错与“尸检”概念
码农高天结合了自己维护开源项目 VizTracer 时刚刚发生的一个真实案例:在给 VizTracer 提 PR(Pull Request)的时候,GitHub Actions 上的持续集成(CI)突然报错挂掉了。CI 抛出的错误日志往往极其简略,例如仅仅给出一句断言失败——“`expected` 不是 `True`”。在自动化测试中,这是一种极其折磨人的典型场景。面对这种故障,开发者常规的做法通常是在本地尝试复现;运气好的时候本地能直接抓到,但常常会出现本地完全无法复现的尴尬局面。这种 bug 可能只在特定的 CI 环境下出现,或者十天半个月才偶尔偶现一次,这会让排查过程变得异常痛苦。
面对这种只有干瘪文字信息、难以在现场抓现行的偶发性故障,许多人开始研究并采用一种被称为 Post-Mortem Debugging(事后调试,形象地翻译为“尸检”)的技术。正如码农高天所概括的那样:“简单的说就是我们如何从已经发生的错误里获取更多的信息去寻找问题的源头。”在 VizTracer 的 CI 流程中,当测试失败时,构建系统会上传一个名为 `coredumpy` 的数据文件。开发者只需要从 GitHub Actions 将这个 dump 结尾的文件下载到本地,就可以直接启动事后调试,还原报错发生那一瞬间的完整现场。
```mermaid flowchart LR accTitle: Post-Mortem Debugging 工作流程 accDescr: 展示从 CI 自动化测试报错,到 coredumpy 导出故障现场,并在本地还原调试的全过程。 subgraph CI["云端 CI 环境"] Test["运行测试套件"] --> Fail["测试 Assert 失败"] Fail --> Dump["coredumpy 截取当前现场"] Dump --> Upload["上传 dump 文件至 CI Artifacts"] end subgraph Local["本地开发环境"] Upload --> Download["开发者下载 dump 文件"] Download --> Inspect["VS Code 插件 / PDB 打开"] Inspect --> Analysis["查看完整调用栈与局部变量"] end ```
---
[01:04](https://www.youtube.com/watch?v=BoGsBGXQ4CA&t=64s) 用 coredumpy 现场“验尸”定位第三方库 Bug
在下载完报错生成的 dump 文件后,码农高天展示了如何在本地进行详细的现场还原。在 VS Code 中,只需在 dump 文件上右键选择“Load with coredumpy”,编辑器就会立刻载入报错发生时的运行切片。界面左下角展示了完整的调用栈(Call Stack),能够精准点击跳转到报错的测试用例 `test_loky_basic` 的崩溃代码行。界面的左上角则列出了当前作用域下的所有局部变量(Local Variables),比如执行过的命令行列表 `command_list` 以及进程执行结果对象 `Result`。
在检查 `Result` 对象时,发现子进程的 `stderr`(标准错误输出)中记录了大量的崩溃内容,说明执行的子进程实际上在内部抛出了异常。由于原始的 `stderr` 打印出来是未经格式化的字节串(`bytes`),在控制台里换行交织、难以辨认,码农高天随即在下方的 Debug Console 中输入 `Result.stderr.decode()`,动态对内存中的局部变量进行求值(evaluation),将它解码成直观易读的字符串。调用栈最底部的信息显示,问题出自依赖包 `loky`:`os.fork_exec` 期望接收 21 个参数,但实际传入了 23 个。高天顺藤摸瓜发现,`loky` 库在上周做了一次改动,在判断逻辑上有 bug 导致传递的参数数量出错,而这个有问题的版本恰恰是在几个小时前刚刚发布的 release。谈到这里,码农高天幽默地甩锅并澄清道:“这个库是几个小时之前刚刚发的 release,所以我之前的测试一直没有问题啊,就最新的这个 PR 才跑出的问题,不是我的锅啊,他们的锅,这里我也跟他们说了是什么问题让他们修一下。”
借助这种 Post-Mortem Debugging 手段,虽然程序早已在远端服务器上执行终止并彻底退出,但开发者依然能够手握“残骸”进行极为深入的交互分析。不仅拥有每一层栈帧的局部变量,还能像断点调试一样在控制台中随意做求值运算;如果有需要,甚至可以在控制台直接对变量进行就地修改(比如把 `result.returncode` 从 `1` 改成 `100`)。对于习惯终端流、不喜欢 VS Code 图形界面的开发者,`coredumpy` 同样无缝支持 PDB 体验,在终端使用交互命令可以执行 `where` 打印调用栈、计算表达式,获得完全一致的事后调试体验。
- 调试定位到的具体报错是 `loky` 包内部调用的 `os.fork_exec` 参数数量不匹配(期望 21 个,实际传入 23 个)。 - 这种报错并不是因为 VizTracer 本身的业务逻辑被改坏,而是上游第三方依赖库在几个小时前刚发布的新版本引入了回归问题。 - `coredumpy` 支持的不仅仅是静态查看,还支持执行任意 Python 表达式求值,并允许开发者直接修改内存变量的值。
---
[03:32](https://www.youtube.com/watch?v=BoGsBGXQ4CA&t=212s) coredumpy 的实现原理与不依赖 Pickle 的核心优势
要在项目中达成这样的调试效果,代码层面的侵入性非常低。以 VizTracer 为例,仅仅需要引入一行代码:`coredumpy.patch_unittest()`。只要加上这句 patch,当任何 `unittest` 用例失败时,系统就会自动将当时的上下文环境打包生成一个 dump 文件,随后配合 GitHub Actions 将 dump 文件作为构建产物(Artifacts)上传即可。这就是码农高天最近独立开发的新工具——`coredumpy`。除了单元测试自动打补丁外,它还提供了多种灵活的接入方式: 1. **Pytest 集成**:使用 Pytest 运行测试时,只需在命令行追加两个参数; 2. **命令行直接运行**:使用 `coredumpy run` 命令行直接拉起待测脚本; 3. **侵入式代码打补丁**:直接在测试框架或主程序入口调用 patch 函数; 4. **手动保存**:在代码任何开发者感兴趣的关键分支处,主动调用手动 dump 接口保存内存快照。
在架构设计上,`coredumpy` 最引人瞩目也是最为关键的特性,就是它**完全没有使用 Python 内置的 `pickle` 模块**。绕开 `pickle` 带来了三项决定性的工程优势: 1. **安全性高**:`pickle` 在反序列化不受信任的数据时存在极大的远程代码执行风险。不使用 `pickle`,开发者便可以安全无虞地在本地载入来自陌生人或外部 CI 跑出来的 dump 文件,不用担心本地机器被植入恶意指令。 2. **极高的容错性与鲁棒性**:传统的 `pickle` 在遇到不支持序列化的对象(如套接字、文件描述符、生成器等)时会直接抛出异常中断过程。而 `coredumpy` 的机制保证了在任何极端复杂的对象图面前,无论如何都能兜底生成一份 dump 文件;即使某些特殊对象无法被完全还原,也不会导致整个 dump 流程直接崩掉崩溃。 3. **彻底解耦运行环境**:`pickle` 严格要求反序列化环境与序列化环境完全一致,如果目标环境中缺少某个模块或类,读取就会直接报错抛异常。而 `coredumpy` 打破了这一限制,在没有安装远端依赖包的本地干净环境中,依然可以自由打开和巡视远端云机器生成的现场。
当然,这种设计也意味着它在某些冷门、极为奇特的数据结构上可能无法自动实现完美还原。针对这一限制,`coredumpy` 提供了可扩展的接口,允许用户针对自己特定的关键数据结构自定义编写编码与解码逻辑。谈及开发该工具的初衷与愿景,码农高天感慨道:“要在任何环境下都能提供信息,而不是 demo 的时候很酷炫,拿到生产环境根本用不了。”虽然 `coredumpy` 目前仍处于相对初期的演进阶段,谈不上完美无缺,但在各种复杂恶劣的环境下已经能够保持自身不崩溃并提供充足的排查线索。目前 VizTracer 已经在生产测试环境中正式实装了 `coredumpy`,高天也呼吁大家尝试接入并前往 GitHub 提交 issue 与意见反馈。
## Notable quotes > [03:32](https://www.youtube.com/watch?v=BoGsBGXQ4CA&t=212s) 要在任何环境下都能提供信息,而不是 demo 的时候很酷炫,拿到生产环境根本用不了。 — 码农高天
## Mentioned 码农高天, coredumpy, VizTracer, Python, GitHub Actions, VS Code, PDB, loky, pickle, pytest, unittest, GitHub
## Video description 这期视频介绍一下什么是post mortem debugging,以及最近写的Python的post mortem debugging工具coredumpy。它可以把你测试报错的那个节点保存下来,让你在本地查看,从而找到问题的源头。
[Source](https://www.youtube.com/watch?v=BoGsBGXQ4CA)