简单记录一下CodeQL的一些基础语法
详细请阅读
https://codeql.github.com/docs/ql-language-reference/
QL是⼀种声明性的,⾯向对象的查询语⾔,经过优化可实现对分层数据结构(尤其是表示软件⼯件的数据
库)的⾼效分析。
数据库是有组织的数据集合。最常⽤的数据库模型是将数据存储在表中的关系模型,⽽SQL(结构化查询
语⾔)是关系数据库最常⽤的查询语⾔。
⾯向对象是QL的重要特征。⾯向对象的好处是众所周知的–它提⾼了模块性,实现了信息隐藏,并允许代
码重⽤。QL在不损害其逻辑基础的情况下提供了所有这些好处。这是通过定义⼀个简单的对象模型实现
的,其中将类建模为谓词,将继承建模为隐含。可⽤于所有受⽀持语⾔的库⼴泛使⽤了类和继承。
from int i where i = -16 select i.abs().sqrt()
from string s1, string s2 where s1 = "try harder" and s2 = "\"nice\"" select s1, s2
from float a, int b where a = 4.28 and b = 6 select a.pow(b), b.sqrt(), a, b
布尔型变量⽤来存放布尔值,即false(假)或者 true(真)。
from boolean b where b = true select b.booleanNot(), b.booleanAnd(b)
所有变量声明均由变量的类型和名称组成。名称可以是任何以⼤写或⼩写字⺟开头的标识符。
QL中的变量与代数或逻辑中的变量的使⽤⽅式相似。它们表示⼀组值,这些值通常受公式限制。
变量声明出现在不同的上下⽂中,例如在select⼦句,量化公式内,作为谓词的参数等
from int i where i in [0 .. 9] select i
仅根据其类型,变量 i 可以包含所有整数。但是,它受公式 i in [0 .. 9] 约束。因此,select⼦句的
结果是介于 0 到 9 之间的数字。
QL中有些变量是free variable,值直接影响使用他们表达式的值,或者使用他们的公式是否成立
有些变量bound variable仅限于特定的值集
"hello".indexOf("l") min(float f | f in [-3 .. 3]) (i + 7) * 3 x.sqrt()
如上四个表达式
第⼀个表达式没有任何变量。它找到 "l" 字符串中出现位置的(从零开始的)索引 "hello" ,因此它的
结果为 2 和 3 。
第二个表达式有变量f,但是不影响表达式的值为-3。所以f为bound variable
第三,四个表达式值取决于变量的值,所以为free variable
同样,如果⼀个公式包含⾃由变量,则该公式可以保留还是不保留,取决于分配给这些变量的值。
比如(i + 7) * 3 instanceof int
i为自由变量,如果i为整数公式成立,为小数则不成立。
表达式的计算结果为⼀组值并具有⼀个类型。
变量引⽤是已声明变量的名称。这种类型的表达式与其所引⽤的变量具有相同的类型。
true
false
0
-45
1.1314
hello
QL中没有“⽇期⽂字”。相反,要指定⼀个date,您应该使⽤ toDate() 谓词将字符串转换为它表示的⽇期。例如, "2016-04-03".toDate() ⽇期是2016年4⽉3⽇,是2000年新年后⼀秒的时间点。 "2000-01-01 00:00:01".toDate()
带括号的表达式是⽤括号 ( 和括起来的表达式 ) 。此表达式的类型和值与原始表达式完全相同。括号可⽤于将表达式分组在⼀起以消除歧义并提⾼可读性。
它由两个表达式分隔, .. 并⽤⽅括号( [ 和 ] )括起来。例如,是有效的范围表达式。它的值是和之间(包括和本身)之间的任何整数 。 [3 .. 7] 表示3和7内所有的整数在有效范围内,开始和结束表达式是整数,浮点数或⽇期。
可以设置⼀个常量范围表达式,例如: [2, 3, 5, 7, 11, 13, 17, 19, 23, 29] 它表示30以内的质数
当您要使用超类型的谓词定义时,可以在谓词调⽤中使用它们。
class A extends int { A() { this = 1 } int getANumber() { result = 2 } } class B extends int { B () {this = 1} int getANumber() {result = 3} } class C extends A, B { int getANumber(){ result = B.super.getANumber() } } from C c select c, c.getANumber()
在下面的示例中,该类 C
继承了谓词的两个定义 getANumber()
- A
⼀个来⾃和⼀个来自 B
。而不是覆盖两个定义,它使用中的定义 B
<aggregate>(<variable declarations> | <formula> | <expression>)
QL中的汇总
from /*...variable declarations...*/ where /*...logical formula...*/ select /*...expressions...*/
from和where部分可选
还有as关键字 order by关键字
from int x, int y where x = 3 and y in [0 .. 3] select x, y, x*y as test, "result:" + test
查询谓词是带有注释的非成员谓词query
。它返回谓词求值的所有元祖
query int getResult(int x, int y){ x = [1..2] and y = 3 and result = x * y }
编写查询谓词⽽不是select⼦句的好处是,您也可以在代码的其他部分调⽤谓词。
例子,输出从0到100的整数
int getANumber(){ result = 0 or result <= 100 and result = getANumber() + 1 } select getANumber()
int getAnEven() { result = 0 or result <= 100 and result = getAnOdd() +1 } int getAnOdd() { result = getAnEven() + 1 } select getAnEven()
查询从0到100 的偶数
A implies B
和(not A) or B
等价class OneTwoThree extends int { OneTwoThree(){ this = 1 or this = 2 or this = 3 } string getAString() { result = "test:" + this.toString() } predicate isEven() { this = 2 } } select 1.(OneTwoThree).getAString()
这些是在类主体中声明的变量。⼀个类在其主体内可以具有任意数量的字段声明(即变量声明)。您可以在类内部的谓词声明中使⽤这些变量。就像变量⼀样 this ,字段必须限制在特征谓词中。
class SmallInt extends int { SmallInt() { this = [1 .. 10] } } class DivisibleInt extends SmallInt { SmallInt divisor; DivisibleInt(){ this % divisor = 0 } SmallInt getADivisor() { result = divisor } } from DivisibleInt i select i, i.getADivisor()
在此示例中,声明引⼊了⼀个字段,将其约束在特征谓词中,然后在成员谓词的声明中使⽤它 。这类似于在部分中通过在select语句中声明变量来引⼊变量 。 SmallInt divisor divisor getADivisor from
如果类从超类型继承成员谓词,则可以覆盖继承的定义。为此,您可以定义⼀个成员谓词,该成员谓词的名称和别名与继承的谓词相同,并添加 override 注解。
class OneTwoThree extends int { OneTwoThree() { this = 1 or this = 2 or this =3 } string getAString() { result = "One, two or three: " + this.toString() } } class OneTwo extends OneTwoThree { OneTwo() { this = 1 or this = 2 } override string getAString() { result = "One or two: "+this.toString() } } from OneTwoThree o select o, o.getAString()
一个类扩展多种类型
class Two extends OneTwo, TwoThree {}
每个查询⽂件(扩展名 .ql )和库⽂件(扩展名 .qll )都隐式定义了⼀个模块。模块的名称与⽂件相同,但⽂件名中的所有空格均由下划线( _ )代替。⽂件的内容构成模块的主体。
有.qll
文件定义。除select子句外,它可以包含下面模块主体列出的任何元素
由.ql
文件定义
定义谓词条件:
非成员谓词,成员谓词,特征谓词
int getSuccessor(int i){// 1. Non-member predicate result = i + 1 and i in [1 .. 9] } class FavoriteNumbers extends int {// 2. Characteristic predicate FavoriteNumbers() { this = 1 or this = 4 or this = 9 } string getName() {// 3. Member predicate for the class `FavoriteNumbers` this = 1 and result = "one" or this = 4 and result = "four" or this = 9 and result = "nine" } } from int i where i = 9 select getSuccessor(i)
int getSuccessor(int i){ result = i + 1 and i in [1 .. 9] } class FavoriteNumbers extends int { FavoriteNumbers() { this = 1 or this = 4 or this = 9 } string getName() { this = 1 and result = "one" or this = 4 and result = "four" or this = 9 and result = "nine" } } from FavoriteNumbers f select f, f.getName()