突破Clang限制:Macroni实现宏感知静态分析与C语言增强

本文介绍Macroni工具如何解决Clang AST缺乏宏溯源信息的问题,通过MLIR实现强类型定义、Linux内核安全检查和Rust风格不安全区域,为C语言提供渐进式增强能力。

Holy Macroni! 渐进式语言增强的配方

尽管Clang被广泛用于重构和静态分析工具,但它存在一个重大缺陷:Clang AST不提供关于给定AST节点来自哪个CPP宏展开的溯源信息;也不将宏展开降级到LLVM中间表示(IR)代码。这使得构建宏感知的静态分析和转换变得极其困难,成为持续研究的领域。

今年夏天在Trail of Bits,我创建了Macroni来简化宏感知静态分析的创建。Macroni允许开发者用宏定义新C语言结构的语法,并用MLIR提供这些结构的语义。Macroni使用VAST将C代码降级到MLIR,并使用PASTA获取宏到AST的溯源信息,将宏也降级到MLIR。开发者随后可以定义自定义MLIR转换器,将Macroni的输出转换为领域特定的MLIR方言以进行更细致的分析。

更强的类型定义

C的typedef用于为底层类型提供有语义意义的名称,但C编译器在类型检查时不使用这些名称,而只对底层类型进行类型检查。当语义类型表示不同格式或度量时,这可能导致简单的类型混淆错误:

1
2
3
4
5
typedef double fahrenheit;
typedef double celsius;
fahrenheit F;
celsius C;
F = C; // 无编译器错误或警告

图1:C类型检查仅考虑typedef的底层类型

使用Macroni,我们可以用宏定义强类型定义的语法,并用MLIR为它们实现自定义类型检查:

1
2
3
#define STRONG_TYPEDEF(name) name
typedef double STRONG_TYPEDEF(fahrenheit);
typedef double STRONG_TYPEDEF(celsius);

图2:使用宏定义强C类型定义的语法

通过将这些宏属性类型定义集成到类型系统中,我们现在可以为它们定义自定义类型检查规则。

增强Linux内核中的Sparse

2003年,Linus Torvalds构建了一个名为Sparse的自定义预处理器、C解析器和编译器。Sparse执行Linux内核特定的类型检查。Sparse依赖于散布在内核代码中的宏,如__user,这些宏在正常构建配置下不执行任何操作,但在定义__CHECKER__宏时展开为__attribute__((address_space(...)))的使用。

使用Macroni,我们可以钩入宏并执行类似Sparse的安全检查和分

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计