gpt4 book ai didi

Clang:如何获取用于常量大小数组声明大小的宏名称

转载 作者:行者123 更新时间:2023-12-03 23:11:45 26 4
gpt4 key购买 nike

TL; 博士;

如何从 callExpr -> arg_0 -> DeclRefExpr 获取用于常量大小数组声明大小的宏名称。

详细问题说明:

最近我开始研究一个需要源到源转换工具进行修改的挑战
带有附加参数的特定函数调用。 Reasearching about how I can acheive 介绍了我
到这个惊人的工具集 Clang。我一直在学习如何使用 libtooling 中提供的不同工具来
实现我的目标。但现在我遇到了一个问题,在这里寻求你的帮助。

考虑下面的程序(我的源代码),我的目标是重写所有对 strcpy 的调用
使用安全版本的 strcpy_s 函数并在新函数调用中添加一个附加参数
即 - 目标指针最大大小。所以,对于下面的程序,我重构的调用就像
strcpy_s(inStr, STR_MAX, argv[1]);

我写了一个 RecursiveVisitor 类并检查 VisitCallExpr 方法中的所有函数调用,以获得最大大小
dest arg 我正在获取第一个 agrument 的 VarDecl 并尝试获取大小(ConstArrayType)。自从
源文件已经过预处理,我看到大小为 2049,但我需要的是宏 STR_MAX
这个案例。我怎么能得到呢?
(使用此信息创建替换,然后使用 RefactoringTool 替换它们)

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define STR_MAX 2049

int main(int argc, char **argv){
char inStr[STR_MAX];

if(argc>1){
//Clang tool required to transaform the below call into strncpy_s(inStr, STR_MAX, argv[1], strlen(argv[1]));
strcpy(inStr, argv[1]);
} else {
printf("\n not enough args");
return -1;
}

printf("got [%s]", inStr);

return 0;
}

最佳答案

正如您所注意到的,源代码已经过预处理,并且所有宏都已展开。因此,AST 将简单地有一个整数表达式作为数组的大小。

关于源位置的一些信息

注意 :您可以跳过它并直接进入下面的解决方案

有关扩展宏的信息包含在 AST 节点的源位置中,通常可以使用 检索。词法分析器 (Clang 的词法分析器和预处理器连接非常紧密,甚至可以被视为一个实体)。这是一个最低限度的工作,不是很明显,但它就是这样。

当您正在寻找一种方法来获取替换的原始宏名称时,您只需要获取拼写(即它在原始源代码中的编写方式),并且您不需要携带太多关于宏定义的内容,函数风格的宏及其参数等。

Clang 有两种不同的位置:来源位置 CharSourceLocation .第一个几乎可以通过 AST 在任何地方找到。它是指代币方面的位置。这解释了为什么开始和结束位置可能有点违反直觉:

// clang::DeclRefExpr
//
// ┌─ begin location
foo(VeryLongButDescriptiveVariableName);
// └─ end location

// clang::BinaryOperator
//
// ┌─ begin location
int Result = LHS + RHS;
// └─ end location

如您所见,这种类型的源位置指向相应 token 的开头。 CharSourceLocation 另一方面,直接指向字符。

所以,为了得到表达式的原文,我们需要转换 来源位置 CharSourceLocation 's 并从源中获取相应的文本。

解决方案

我已经修改了您的示例以显示宏扩展的其他情况:

#define STR_MAX 2049
#define BAR(X) X

int main() {
char inStrDef[STR_MAX];
char inStrFunc[BAR(2049)];
char inStrFuncNested[BAR(BAR(STR_MAX))];
}

以下代码:

// clang::VarDecl *VD;
// clang::ASTContext *Context;
auto &SM = Context->getSourceManager();
auto &LO = Context->getLangOpts();
auto DeclarationType = VD->getTypeSourceInfo()->getTypeLoc();

if (auto ArrayType = DeclarationType.getAs<ConstantArrayTypeLoc>()) {
auto *Size = ArrayType.getSizeExpr();

auto CharRange = Lexer::getAsCharRange(Size->getSourceRange(), SM, LO);
// Lexer gets text for [start, end) and we want him to grab the end as well
CharRange.setEnd(CharRange.getEnd().getLocWithOffset(1));

auto StringRep = Lexer::getSourceText(CharRange, SM, LO);
llvm::errs() << StringRep << "\n";
}

为代码段生成此输出:
STR_MAX
BAR(2049)
BAR(BAR(STR_MAX))

我希望这些信息对你有用。使用 Clang 进行愉快的黑客攻击!

关于Clang:如何获取用于常量大小数组声明大小的宏名称,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56512050/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com