Clang 获取全部”;malloc“;使用ASTMatcher调用

Clang 获取全部”;malloc“;使用ASTMatcher调用,clang,abstract-syntax-tree,Clang,Abstract Syntax Tree,我正在尝试使用ASTMatcher以叮当声获取所有malloc调用。这是代码示例: Finder.addMatcher( callExpr( hasParent(binaryOperator( hasOperatorName("=")).bind("assignment")), declRefExpr(to(functionDecl(hasName("malloc"))))).bind("functionCall"),

我正在尝试使用
ASTMatcher
以叮当声获取所有
malloc
调用。这是代码示例:

Finder.addMatcher(
      callExpr(
        hasParent(binaryOperator(
          hasOperatorName("=")).bind("assignment")),
          declRefExpr(to(functionDecl(hasName("malloc"))))).bind("functionCall"),
      &HandlerForFunctionCall);
它编译得很好。但我仍然无法接到任何
malloc
电话。如何使用clang ASTMatcher获得所有
malloc
调用?

问题
malloc
函数的签名定义如下:

void*malloc(大小);
为了将
malloc
的返回值分配给除
void*
之外的任何类型的指针,必须强制转换它。 当C++需要显式地强制转换时,C编译器会为您隐式地进行。所以即使你写

int*a=malloc(sizeof(*a));
编译器将隐式转换RHS表达式。这相当于

int*a=(int*)malloc(sizeof(*a));
您使用的是
hasParent
缩小匹配器,,它只匹配直接的父项,而不匹配任何祖先。 因此,你的匹配者只匹配没有任何类型施法的任务

在您的
declRefExpr
中也会发生类似的情况。 C标准说函数自动衰减为指向函数的指针。 Clang隐式地将
malloc
强制转换为
void*(*)(size\u t)
,这打破了匹配器的层次结构

可能的解决方案 这取决于你到底想做什么。 首先,您通常可以使用以下代码段修复选择malloc函数的部件:

callExpr(被调用方(functionDecl(hasName(“malloc”)))
其余部分取决于您要选择的内容。 如果您只对匹配上面第一个示例中的直接赋值感兴趣,那么可以使用
ignoringImpCasts
matcher。 由于某些原因,我无法在您编写匹配器时将其插入匹配器,因此只需反转匹配器即可。 看起来像这样:

二进制运算符(
hasOperatorName(“=”),
hasRHS(忽略输入)(
呼叫者(
被调用方(functionDecl(hasName(“malloc”))
).bind(“函数调用”)
))
).bind(“转让”)
如果您还想像第二个示例中那样包含显式强制转换,请改用
ignoringParenImpCasts

二进制运算符(
hasOperatorName(“=”),
hasRHS(忽略PARENIMPCASTS)(
呼叫者(
被调用方(functionDecl(hasName(“malloc”))
).bind(“函数调用”)
))
).bind(“转让”)
如果您对包含
malloc
的任意表达式的所有赋值感兴趣,请改用
hasascentor
。它不仅匹配直接父节点,而且会一直遍历,直到与您的节点匹配为止:

callExpr(
被调用方(functionDecl(hasName(“malloc”)),
有祖先(
binaryOperator(hasOperatorName(“=”).bind(“赋值”)
)
).bind(“函数调用”)
还有一件事。 您可能只对直接匹配源代码中定义的内容感兴趣,而不是在包含的头文件中。 只需将
除非(IsExpansionSystemHeader())
添加到顶级匹配器,它将从系统头中排除所有定义

请注意,这段代码已经用LLVM 3.7进行了测试,将来的更改可能会破坏它

如何调试 好吧,那我们他妈的怎么知道这些? 事实证明,这个叮当声已经为您提供了所需的一切:) 具体来说,您可能会对两个特性感兴趣

当您使用
-Xclang ast dump-fsyntax only
调用Clang时,它将打印出漂亮多彩的翻译单元ast。当您发现包含来自系统头的所有声明的巨大序言时,不要感到惊讶,因为它必须首先运行预处理器来生成AST。例如:

$clang-Xclang-ast dump-fsyntax-only example.c
...
`-FunctionDecl 0x3f2fc28行:19:5主'int()'
`-复合材料STMT 0x3f307b8
|-二进制运算符0x3f2ff38'int*'''
||-DeclRefExpr 0x3f2fd40'int*'左值变量0x3f2f388'a'int*'
|`-ImplicitCastExpr 0x3f2ff20'int*'
|`-CallExpr 0x3f2fef0'void*'
||-ImplicitCastExpr 0x3f2fed8'无效*(*)(无符号长)'
|| `DeclRefExpr 0x3f2fd68'void*(无符号长)'Function 0x3f1cdd0'malloc''void*(无符号长)'
|`-BinaryOperator 0x3f2fe88'无符号长'*'
||-ImplicitCastExpr 0x3f2fe70“无符号长”
|| `ImplicitCastExpr 0x3f2fe58'int'
||`-DeclRefExpr 0x3f2fd90'int'左值变量0x3f2f488'n'int'
|`-UnaryExprOrTypeTraitExpr 0x3f2fe38'无符号长'sizeof
|`-ParenExpr 0x3f2fe18'int'左值
|`-UnaryOperator 0x3f2fdf8'int'左值前缀'*'
|`-ImplicitCastExpr 0x3f2fde0'int*'
|`-DeclRefExpr 0x3f2fdb8'int*'左值变量0x3f2f388'a''int*'
...
还有一个clang查询,如果您从源代码编译它,它将与clang一起构建。 它是libTooling的一个很好的例子,同时也是开发中一个绝对惊人的帮助。 您只需在示例源文件上运行它,并使用它测试匹配器(注意,它隐式地将“root”绑定到完整的匹配器):

$/bin/clangqueryexample.c--
clangquery>match callExpr(被调用方(functionDecl(hasName(“malloc”)))),hasascentor(binarymoperator(hascopername(“=”)).bind(“赋值”).bind(“functionCall”)
匹配#1:
/vagrant/tests/true-valid memsafety.c:22:3:注:“分配”在此绑定
a=malloc(n*sizeof(*a));
^~~~~~~~~~~~~~~~~~~~~~~~~~~
/vagrant/tests/true-valid-memsafety.c:22:7:注意:“functionCall”在这里绑定
a=malloc(n*sizeof(*a));
^~~~~~~~~~~~~~~~~~~~~~~
/vagrant/tests/true-valid-memsafety.c:22:7:注:“root”在此绑定
a=malloc(n*sizeof(*a));
^~~~~~~~~~~~~~~~~~~~~~~
匹配#2:
/vagrant/tests/true-valid memsafety.c:23:3:注:“分配”在此绑定
b=malloc(n*sizeof(*b));
^~~~~~~~~~~~