哈希合并和值编号¶
您可以使用专门的 CodeQL 库来识别在 C 和 C++ 代码库中语法上相同或在运行时计算相同值的表达式。
关于哈希合并和值编号库¶
在 C 和 C++ 数据库中,抽象语法树中的每个节点都由一个单独的对象表示。这允许分析和结果显示都引用语法片段的特定出现。但是,确定两个表达式是否等效(无论是语法上还是语义上)通常很有用。
哈希合并库(在 semmle.code.cpp.valuenumbering.HashCons
中定义)提供了一种机制来识别具有相同语法结构的表达式。全局值编号库(在 semmle.code.cpp.valuenumbering.GlobalValueNumbering
中定义)提供了一种机制来识别在运行时计算相同值的表达式。这两个库都将每个函数中的表达式划分成由对象表示的等效类。每个 HashCons
对象代表一组具有相同解析树的表达式,而 GVN
对象代表一组始终计算相同值的表达式。有关更多信息,请参阅维基百科上的 哈希合并 和 值编号。
示例 C 代码¶
在以下 C 程序中,x + y
和 x + z
将被分配相同的数值,但哈希合并不同。
int x = 1;
int y = 2;
int z = y;
if(x + y == x + z) {
...
}
但是,在下一个示例中,x + y
的使用将具有不同的数值,但相同的哈希合并。
int x = 1;
int y = 2;
if(x + y) {
...
}
x = 2;
if(x + y) {
...
}
值编号¶
值编号库(在 semmle.code.cpp.valuenumbering.GlobalValueNumbering
中定义)提供了一种机制来识别在运行时计算相同值的表达式。当您主要关注的是正在产生的值或最终运行的机器码时,值编号很有用。例如,值编号可用于确定是否对与保护它的操作相同的数值进行了检查。
值编号 API¶
值编号库主要通过 GVN
类公开其接口。每个 GVN
实例代表一组始终计算相同值的表达式。要获取特定 GVN
代表的集合中的表达式,请使用 getAnExpr()
成员谓词。
要获取 Expr
的 GVN
,请使用 globalValueNumber
谓词。
注意
虽然
GVN
类具有toString
和getLocation
方法,但这些方法仅作为调试辅助手段提供。它们给出了集合中任意Expr
的toString
和getLocation
。
为什么不是谓词?¶
这个库的明显接口将是一个谓词 equivalent(Expr e1, Expr e2)
。但是,这个谓词将非常大,对于每组等效表达式,将具有二次数量的行。通过使用类作为中间步骤,可以将行数保持为线性,因此可以进行缓存。
示例查询¶
此查询使用 GVN
类来识别对 strncpy
的调用,其中大小参数是从源代码而不是目标代码派生的
from FunctionCall strncpy, FunctionCall strlen
where
strncpy.getTarget().hasGlobalName("strncpy") and
strlen.getTarget().hasGlobalName("strlen") and
globalValueNumber(strncpy.getArgument(1)) = globalValueNumber(strlen.getArgument(0)) and
strlen = strncpy.getArgument(2)
select ci, "This call to strncpy is bounded by the size of the source rather than the destination"
哈希合并¶
哈希合并库(在 semmle.code.cpp.valuenumbering.HashCons
中定义)提供了一种机制来识别具有相同语法结构的表达式。当您主要关注代码文本时,哈希合并很有用。例如,哈希合并可用于检测函数内的重复代码。
哈希合并 API¶
哈希合并库主要通过 HashCons
类公开其接口。每个 HashCons
实例代表一个函数内具有相同语法的表达式集(包括引用相同的变量)。要获取特定 HashCons
代表的集合中的表达式,请使用 getAnExpr()
成员谓词。
注意
虽然
HashCons
类具有toString
和getLocation
方法,但这些方法仅作为调试辅助手段提供。它们给出了集合中任意Expr
的toString
和getLocation
。
要获取 Expr
的 HashCons
,请使用 hashCons
谓词。
示例查询¶
import cpp
import semmle.code.cpp.valuenumbering.HashCons
from IfStmt outer, IfStmt inner
where
outer.getElse+() = inner and
hashCons(outer.getCondition()) = hashCons(inner.getCondition())
select inner.getCondition(), "The condition of this if statement duplicates the condition of $@",
outer.getCondition(), "an enclosing if statement"