2 QL 语法
2.1 谓词
在 CodeQL 中,函数并不叫“函数”,叫做 Predicates
(谓词)。为了便于说明,下文中的函数与谓词都是指代同一个内容。
谓词的定义方式如下:
predicate name(type arg)
{
statements
}
定义谓词有三个要素:
- 关键词 predicate(如果没有返回值),或者结果的类型(如果当前谓词内存在返回值)
- 谓词的名称
- 谓词的参数列表
- 谓词主体
2.1.1 无返回值的谓词
- 无返回值的谓词以
predicate
关键词开头。若传入的值满足谓词主体中的逻辑,则该谓词将保留该值。 - 无返回值谓词的使用范围较小,但仍然在某些情况下扮演了很重要的一个角色
- 举一个简单的例子
predicate isSmall(int i) {
i in [1 .. 9]
}
from int i
where isSmall(i) // 将整数集合 i 从正无穷大的数据集含,限制至 1-9
select i
// 输出 1-9 的数字
若传入的 i
是小于 10 的正整数,则 isSmall(i)
将会使得传入的集合 i
只保留符合条件的值,其他值将会被舍弃。
2.1.2 有返回值的谓词
当需要将某些结果从谓词中返回时,与编程语言的 return 语句不同的是,谓词使用的是一个特殊变量 result
。谓词主体的语法只是为了表述逻辑之间的关系,因此务必不要用一般编程语言的语法来理解。
int getSuccessor(int i) {
// 若传入的 i 位于 1-9 内,则返回 i+1
result = i + 1 and i in [1 .. 9]
}
select getSuccessor(3) // 输出 4
select getSuccessor(33) // 不输出任何信息
在谓词主体中, result
变量可以像一般变量一样正常使用,唯一不同的是这个变量内的数据将会被返回。
string getANeighbor(string country) {
country = "France" and result = "Belgium"
or
country = "France" and result = "Germany"
or
country = "Germany" and result = "Austria"
or
country = "Germany" and result = "Belgium"
}
select getANeighbor("France")
// 返回两个条目,"Belgium" 与 "Germany"
谓词不允许描述的数据集合个数 不限于有限数量大小 的。举个例子:
// 该谓词将使得编译报错
int multiplyBy4(int i) {
// i 是一个数据集合,此时该集合可能是「无限大小」
// result 集合被设置为 i*4,意味着 result 集合的大小有可能也是无限大小
result = i * 4
}
但如果我们仍然需要定义这类函数,则必须 限制集合数据大小 ,同时添加一个 bindingset
标注。该标注将会声明谓词 plusOne
所包含的数据集合是有限的,前提是 i
绑定到有限数量的数据集合。
bindingset[x] bindingset[y]
predicate plusOne(int x, int y) {
x + 1 = y
}
from int x, int y
where y = 42 and plusOne(x, y)
select x, y
2.2 类
在 CodeQL 中的类, 并不意味着建立一个新的对象 ,而只是表示特定一类的数据集合,定义一个类,需要三个步骤:
- 使用关键字
class
- 起一个类名,其中类名必须是首字母大写的。
- 确定是从哪个类中派生出来的
其中,基本类型 boolean
、 float
、 int
、 string
以及 date
也算在内。
如下是官方的一个样例:
class OneTwoThree extends int {
OneTwoThree() { // characteristic predicate
this = 1 or this = 2 or this = 3
}
string getAString() { // member predicate
result = "One, two or three: " + this.toString()
}
predicate isEven() { // member predicate
this in [1 .. 2]
}
}
from OneTwoThree i
where i = 1 or i.getAString() = "One, two or three: 2"
select i
// 输出 1 和 2
其中, 特征谓词 类似于类的构造函数,它将会进一步限制当前类所表示数据的集合。它将数据集合从原先的 Int
集,进一步限制至 1-3 这个范围。 this
变量表示的是当前类中所包含的数据集合。与 result
变量类似, this
同样是用于表示数据集合直接的关系。
此外,在特征谓词中,比较常用的一个关键字是 exists
。该关键字的语法如下:
exists(<variable declarations> | <formula>)
// 以下两个 exists 所表达的意思等价。
exists(<variable declarations> | <formula 1> | <formula 2>
exists(<variable declarations> | <formula 1> and <formula 2>
这个关键字的使用引入了一些新的变量。如果变量中至少有一组值可以使 formula 成立,那么该值将被保留。
一个简单的例子:
import cpp
class NetworkByteSwap extends Expr{
NetworkByteSwap()
{
// 对于 MacroInvocation 这个大类的数据集合来说,
exists(MacroInvocation mi |
// 如果存在宏调用,其宏名称满足特定正则表达式
mi.getMacroName().regexpMatch("ntoh(s|l|ll)") and
// 将这类数据保存至当前类中
this = mi.getExpr()
)
}
}
from NetworkByteSwap n
select n, "Network byte swap"
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论