返回介绍

2 QL 语法

发布于 2024-09-12 23:59:25 字数 4172 浏览 0 评论 0 收藏 0

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
  • 起一个类名,其中类名必须是首字母大写的。
  • 确定是从哪个类中派生出来的

其中,基本类型 booleanfloatintstring 以及 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文