尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

如何对Python解释器做模糊测试?Monty fuzz Target设计与实战

如何对Python解释器做模糊测试?Monty fuzz Target设计与实战 如何对Python解释器做模糊测试Monty fuzz Target设计与实战【免费下载链接】montyA minimal, secure Python interpreter written in Rust for use by AI项目地址: https://gitcode.com/GitHub_Trending/monty3/montyMonty是一个用 Rust 编写的极简、安全 Python 解释器专为运行 AI 生成的代码而设计。这篇文章带你拆解它的fuzz target模糊测试目标设计如何用cargo-fuzz给 Python 解释器做模糊测试fuzzing以及如何设计出真正打得动解释器的测试输入。如果你写过解释器、沙箱或者想知道随机乱敲代码会不会把解释器敲崩这篇实战指南会给你一套可以直接抄的思路。为什么 Python 解释器需要模糊测试Monty 的定位是语言级沙箱它要执行的代码由语言模型写出、没有人 review详见 docs/security.md。这类代码天然充满语法残缺的乱码无限循环、x * 10**12这类内存炸弹边界值堆叠的递归和嵌套表达式单元测试只能覆盖你想到的 case而模糊测试fuzzing用随机/半随机的输入暴力覆盖你没想到的。对解释器来说最硬的指标只有一条任何输入都不能让解释器 panic 或崩溃——报错是允许的崩溃不行。Monty 的模糊测试工程放在独立的monty-fuzzcrate 里整体结构非常薄crates/fuzz/Cargo.toml声明依赖arbitrary和libfuzzer-sys并注册两个 fuzz 目标crates/fuzz/fuzz_targets/string_input_panic.rs字符串级模糊测试crates/fuzz/fuzz_targets/tokens_input_panic.rs结构化 token 级模糊测试Fuzz Target 一把随机字符串直接丢给解释器第一个目标string_input_panic的思路简单粗暴——任意字节串当 Python 代码执行。它只做三件事解析调用MontyRun::new构造运行器解析失败直接return对随机输入来说这是预期行为执行在受限资源下运行所有运行期错误一律忽略断言没有显式断言——fuzzer 的断言就是没 panic 就是过fuzz_target!(|code: String| { let Ok(runner) MontyRun::new(code.to_owned(), fuzz.py, vec![], CompileOptions::default()) else { return; // Parse errors are expected for random input }; let _ runner.run(vec![], fuzz_limits(), PrintWriter::Disabled); });这段代码里最关键的是fuzz_limits()——每次 fuzz 都套用极苛刻的资源限制限制项取值目的max_memory1 MB防止内存炸弹把 fuzz 进程拖垮max_duration100 ms防止死循环挂住整个 fuzz 会话 这是可复用的经验给解释器做 fuzz 必须先套资源限制否则第一个被发现的bug往往是你的 fuzzer 自己 OOM。Monty 的资源限制机制ResourceTracker/ResourceLimits本身也是对未信任代码的防御手段完整说明见 docs/resource-limits.md实现层面的预检查在 crates/monty/src/resource_checks.rs。Fuzz Target 二用半结构化 token打得更有针对性纯随机字符串有个天然缺陷几乎全是解析错误根本进不了解析器深处更到不了字节码 VM。第二个目标tokens_input_panic的解法很聪明——不生成随机字符而是从一个词法文法里随机抽 token 再拼成代码。它的Token枚举把 Python 语法切成几个积木箱完整清单见 tokens_input_panic.rs字面量普通/ f-string / raw / bytes 字符串int、float刻意回避inf/NaN、True/False/None标识符常见变量名x、foo、result…和常见属性名append、pop、split…运算符全套二元/一元/比较/增强赋值运算符关键字if、for、try、async、lambda、import…结构与标点括号、缩进级别0~4 级、换行、注释每个 token 都实现了Display拼起来就是一段语法上看起来像 Python的代码。这样 fuzzer 的变异精力被集中在了真正容易出问题的地方运算符组合、括号配对、缩进错乱、关键字错位——正是解析器和求值逻辑最容易 panic 的地带。两个容易被忽略的工程细节 ️1. 用Arbitrary派生代替手写输入生成。所有枚举类型一行#[derive(Arbitrary)]就让arbitrary库自动生成了随机值结构化输入几乎没有额外代码。2. 自定义Debug输出让复现不丢上下文。默认的VecToken打印出来是Token(String(...)), Token(BinOp(Div))...很难还原现场。Monty 给Tokens包装类型实现了fmt::Debug同时输出 token 序列和拼好的 Python 源码impl fmt::Debug for Tokens { fn fmt(self, f: mut fmt::Formatter_) - fmt::Result { f.debug_struct(Tokens) .field(tokens, self.0) .field(code, self.to_code()) // 直接打印生成的代码 .finish() } }当 fuzzer 报出一个 crash 时你拿到的不是几百个抽象 token而是一段可以直接复制粘贴复现的 Python 代码。这一行设计决定了模糊测试的调试成本是天还是分钟。如何运行 Monty 的模糊测试Monty 使用标准的cargo-fuzz工具链运行方式如下需要先安装 cargo-fuzz 组件# 克隆仓库 git clone https://gitcode.com/GitHub_Trending/monty3/monty cd monty/crates/fuzz # 运行字符串级 fuzz 目标 cargo fuzz run string_input_panic # 运行结构化 token fuzz 目标 cargo fuzz run tokens_input_panic发现 crash 后复现用例会保存在crates/fuzz/artifacts/下配合上面提到的Debug输出可以直接还原触发的源码。带走这三点给你的解释器也做一套 fuzz断言要弱对解释器做 fuzz目标不是输出正确而是绝不 panic把正常错误全部吞掉只让崩溃说话。输入要分层一层纯随机覆盖解析器入口一层结构化 token深入语义层两层的互补性正是 Monty 双目标的设计。限制要硬内存、时长、递归深度都要设上限fuzz 会话本身不能被被测代码拖死。延伸阅读沙箱安全模型与崩溃隔离 → docs/security.md资源限制的四项配置 → docs/resource-limits.mdfuzz 目标配置 → crates/fuzz/Cargo.toml。【免费下载链接】montyA minimal, secure Python interpreter written in Rust for use by AI项目地址: https://gitcode.com/GitHub_Trending/monty3/monty创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表