LWN:Coccinelle的Rust支持!

关注了就能看到更多这么棒的文章哦~

Coccinelle for Rust

By Daroc Alden
September 30, 2024
Kangrejos 2024
Gemini-1.5-flash translation
https://lwn.net/Articles/991399/

Tathagata Roy 一直致力于将 Coccinelle 工具应用于 Rust 代码的重构自动化(当然还保留其他用途)。Roy 在 Kangrejos 上展示了他的工作成果,包括在处理 Rust 更复杂的控制流和语法时所采用的创造性方法。

Roy 从介绍 Coccinelle 在内核中的用途 开始。Linux 代码库庞大,经常需要将对内部 API 的更改反映到大量的驱动程序或其他内核组件中;Coccinelle 允许维护人员 用一种特殊语言编写补丁,这些补丁可以自动应用到整个代码库,使大范围的变更变得更加容易。这种类型的更改需要专门的工具,因为解析 C 源代码并非易事。

尽管内核中的 Rust 代码要少得多,但如果现有的内核维护人员熟悉的工具也能用于 Rust 代码,那将是一件好事。Roy 展示了一个示例,说明了这种情况可能是什么样的;简而言之,作者将遵循与 C 代码相同的流程。为了构建用于 Coccinelle 的语义补丁,程序员会选择一个用于目标更改的典型差异,然后通过添加“表达式变量”使其更通用。一个 Rust API 更改的补丁示例可能如下所示:

@@
expression tcx, arg;
@@

- tcx.type_of(arg)
+ tcx.bound_type_of(arg).subst_identity()

该补丁找到 .type_of() 的使用并将其重写为调用不同的函数,即使该方法是在复杂表达式上或使用复杂表达式进行调用。

然而,隐藏在水面之下的,是要正确地支持 Rust 所需的大量的思考。Roy 强调的最大问题是更复杂的控制流。为了正确地应用补丁,Coccinelle 需要将补丁表达式与程序的抽象语法树 (AST) 匹配。Roy 解释说,这需要了解程序的控制流。在 Rust 中,这包括比如 if 表达式这样的细微差别。在 Rust 中,如下代码是有效代码:

println!("{}", if boolean { "string 1" } else { "string 2" })

这会导致一些违反直觉的控制流图(control-flow graphs)。Roy 最近工作的核心是将 Rust 程序的表示形式转化为 Coccinelle 现有模式匹配算法可以处理的形式。他的方法通过对 AST 进行先序遍历来实现,将 AST 转换为程序中控制流的表示形式,然后对其进行匹配,而不是对原始 AST 进行匹配。他说,这种方法有效,但仍然存在一些问题。它会产生非常“庞大”的图,需要 Coccinelle 耗费时间进行处理,并且使调试变得困难。

通过消除只有一个子节点的中间节点,可以将图压缩 4-5 倍,但这并不是一个完整的解决方案。Roy 解释说,这种表示形式的另一个问题是如何处理元变量(如上面提到的 tcx 和 arg )。元变量可以代表任何表达式,这使得将它们与控制流图的部分进行匹配变得有些棘手。因此,为了使匹配更容易,图还要用额外的边进行装饰,这些边指向节点的下一个子节点(或最近的堂兄弟)。这使得高效地确定表达式在哪里结束变得容易得多。

aa1e780366a29939f200158126e97ec5.png

这种新的内部表示并不是 Coccinelle 正在进行的唯一工作。Roy 解释说,用于 Rust 的 Coccinelle 最近添加了一个省略号运算符,它可以代表连接两个节点的任何控制流路径。这使得编写匹配由任意代码分隔的两个不同调用位置的规则变得更加容易。

匹配包含省略号的模式需要考虑不同的潜在匹配,这意味着要考虑多个备选方案,因此它是一种析取(disjunction)形式。以前,Coccinelle 仅允许表达式的析取;现在,Roy 正在努力将析取推广到包括任意语句。事实证明,这对 Rust 代码来说尤其困难,主要就是因为 Coccinelle 的解析方法。Coccinelle 的 C 解析器是手工编写的,因此可以包含扩展,将语义补丁中的 Coccinelle 特定构造解析为与相邻 C 代码相同的结构。另一方面,Coccinelle 的 Rust 解析器是 rust-analyzer 项目 提供的标准解析器——因为 Roy 不想重新编写整个 Rust 解析器,也不想费心来将其保持最新。这使得解析 Coccinelle 用于析取的语法变得很棘手。

Roy 选择的解决方案是通过简单的文本替换将析取转换为 Rust 宏,使用 rust-analyzer 解析生成的 Rust 代码,然后识别宏名称并对其进行特殊处理。这样做的好处是可以更容易地进行解析,但缺点是不允许对属性、枚举备选方案或无法用宏包装的其他结构进行析取。Roy 强调,对析取的支持仍然是一个正在进行的工作。

在将工作称为完成之前,Roy 希望看到另外两个问题得到解决:允许 Coccinelle 处理实际的宏(他将其描述为“AST 中的一个难题”)以及并行处理补丁。完成这些工作后,Coccinelle 有望证明它对 Rust 程序员来说与对 C 程序员一样有用。希望使用当前(实验性)对 Rust 支持的人员可以在 Roy 的开发版本 中找到它,该版本位于 CoccinelleForRust 存储库 中——尽管链接的分支不包括正在进行的析取支持。

全文完
LWN 文章遵循 CC BY-SA 4.0 许可协议。

欢迎分享、转载及基于现有协议再创作~

长按下面二维码关注,关注 LWN 深度文章以及开源社区的各种新近言论~

8e633c10233197185e500d4a8316ff07.jpeg

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值