我有looking for个help detect工具来阻止程序作为64位代码正常运行的solution provided by ahmeddirie错误。最近,我一直在玩弄Klocwork及其自定义检查器功能,这让我可以使用XPath将源代码导航为树。这对于正则表达式的“更聪明”替代方法很有用,但我无法让它知道类型。
例如,假设我想找到使用for
或int
计算的long
循环的每个实例。以下代码很容易找到。
for (int i = 0; i < 10; i++)
// ...
搜索此代码很简单,因为变量定义就在循环内部。但是,请考虑以下示例。
int i;
// ...
for (i = 0; i < 10; i++)
// ...
这很难找到,因为变量定义与循环是分开的,并且必要的XPath表达式要么笨拙,要么容易出错。
那么,自定义Klocwork规则是否可以找到类似这样的表达式,其中包含类型感知,包括解析typedef
和#define
语句?是否有其他工具可以做到这一点?
编辑1:请考虑以下示例。
typedef int myint;
void Foo() {
int i;
for (i = 0; i < 10; i++) {
Bar();
}
myint j;
for (j = 0; j < 10; j++) {
Bar();
}
}
{{3}}找到第一个循环,因为i
的类型明确定义为int
。但是,找不到第二个循环,因为typedef模糊了底层类型。什么工具以一种方式跟踪类型,以便将第二个循环变量j
识别为int
?
答案 0 :(得分:2)
您可以使用Clang(http://clang.llvm.org)甚至Elsa(https://github.com/dsw/oink-stack/)在类型传播和模板实例化后生成AST。两者都提供了一个不错的C ++ API和一些将AST转储成可读文本的方法。这两个选项都是免费的。
答案 1 :(得分:1)
我工作的公司,Semantic Designs Inc.提供工具整合 用于分析和转换计划的一般基础设施 各种编程语言的特定分析组件。 这些被称为DMS。在C ++的情况下,DMS包括 集成的词法分析器,预处理器,解析器以及名称和类型 每个GCC3,GCC4,ISO14882c1998(ANSI)的分辨率组件, Visual C ++ 6.0和非托管Visual Studio 2005 C ++。对于各种 C的方言,也存在控制流分析,副作用 分析器和符号依赖性分析器,使用哪种工具 指针检查器,无效代码移除器,功能分析器和程序 切片机已经实施。
名称和类型解析组件提供完整的符号表 信息和查找功能,以便参考 标识符可以很容易地与其类型和其他类型相关联 声明性信息。信息就像被捕获的那样 由编译器使用,但与抽象语法树一起保留 以适合任何工具的自适应重复使用的形式 成分
Semantic Designs最近构建了一个自定义工具 与循环中的索引变量类型有关 声明,例如在您的示例中。在这种情况下,问题是 升级使用-fno-for-scope编译器开关的GCC2代码, 它为循环变量提供了范围解析规则 后来的GCC方言支持。该工具必须转换循环, 将循环变量的声明移动到外部上下文中 保留了-fno-for-scope范围规则。凡这样的变化 没有必要,没有改变。
因此,该工具必须识别与每个参考相关联的类型 到一个循环变量,在屏蔽范围的情况下区分,和 重构代码,以便GCC3和GCC4名称解析 导致与GCC2相同的语义解释 -fno换范围。这需要能够访问符号表 与每个变量引用相关的信息,在这种情况下 移动代码的地方,重建正确的语法 其声明被移动的任何变量的类型声明。 DMS提供的符号表和标识符引用表 C ++名称和类型解析组件包含所有必需的 信息,以及用于重建规定类型语法的模块 允许合成正确的新类型声明。
例如,请考虑以下示例:
// loop variable hides variable in global scope
// will change meaning without -fno-for-scope
// fix: move decl. of cnt before for-loop
// optionally rename globcnt loop variable
float globcnt = 0.0;
int Foo::foo3() {
for (int globcnt = 0; globcnt < 5; globcnt++) {
globalInt += globcnt;
}
globalInt += 2*globcnt + 1;
return 0;
}
GCC2 -fno-for-scope语义表明对globcnt的引用 循环外部是循环变量,即使GCC3会 考虑循环变量超出范围并解析引用 全局变量。该工具将此代码转换为:
float globcnt = 0.0;
int Foo::foo3() {
int globcnt = 0;
for (; globcnt < 5; globcnt++) {
globalInt += globcnt;
}
globalInt += 2*globcnt + 1;
return 0;
}
如果代码没有被转换,GCC4总会返回一个 来自Foo的值为1:foo3。但是,转变了价值 受到最初设计的循环迭代的影响 GCC2。该工具必须认识到对globcnt的最终引用 是int类型的局部变量,而不是全局变量 键入float,它可以通过符号表查找来执行,并执行操作 相应
另一方面,该工具在以下代码中识别出来 在循环之外没有对i的引用,所以这是可以接受的 (并且首选)保持循环变量声明完整。
int Foo::foo0() {
for (int i = 0; i < 10; i++) {
globalInt += i*i;
}
return 0;
}
答案 2 :(得分:1)
不完全确定这是否是您想要的,但您始终可以使用内置函数轻松解析类型。例如,回答你的问题(虽然可能不是你的潜在需求):
//ForStmt / Init::ExprStmt / Expr::BinaryExpr [ $type := Left.getTypeName() ] [ $type = 'int' | $type.contains('long') ]
这将找到非常方便地使用'int'或'long int'计数器类型的'for'循环,并且显然可以应用于基于表达式的语句的任何元素。
类型定义适用于此类操作,无论是程序员定义还是语言定义。但是,预处理器定义只会产生它们的本机语言类型(即宏本身不能通过KAST进行操作,只能扩展到它)。