前言

由于CodeQL的特殊语法,其查询语句多数通过各种api调用来实现,因此,常常出现一个问题,想写代码不知该如何下手,看别人代码看不懂,直接看源码也不适合新手

同时CodeQL的官方文档其实也并非足够友好

在这里可以找到c/c++的api

CodeQL api for c/c++

官方文档提供了查询功能,但是解释得有些潦草

因此就需要借助各种示例来堆经验,才能独立写出合适的查询语句

本章借助一些基本示例来学习:

some examples

如果你也对这些示例感兴趣,可以本地编译一个玩玩,不过建议还是可以到lgtm上面玩,数据库多,用起来也方便

lgtm

addressof.ql

1
2
3
4
5
6
7
8
9
10
11
/*
* @description Finds address-of expressions (`&`) that take the address of a reference variable
*/

import cpp

from AddressOfExpr addr, VariableAccess access //取地址符 变量
where
access = addr.getOperand() and //找到使用取地址符"&"的地方;getOperand,获取此一元操作得操作数赋值给access
access.getTarget().getType() instanceof ReferenceType //判断该操作数是否属于引用的类型
select addr

该查询的作用为找到引用,注意是引用,和取地址是有区别的

查询结果示例:

image.png

arrayaccess.ql

1
2
3
4
5
6
7
8
9
/**
* @description Finds array access expressions with an index expression consisting of a postfix increment (`++`) expression.
*/

import cpp

from ArrayExpr a //ArrayExpr,数组访问表达式
where a.getArrayOffset() instanceof PostfixIncrExpr //getArrayOffset为获取给出**数组索引的表达式;**PostfixIncrExpr,后缀增量表达式++
select a

查找具有由后缀增量 (++) 表达式组成的索引表达式的数组访问表达式,即查找对某数组元素进行++操作的地方

示例:

image _1_.png

castexpr.ql

1
2
3
4
5
6
7
8
9
10
11
/**
* @description Finds casts from a floating point type to an integer type
*/

import cpp

from Cast c //强制转换表达式
where
c.getExpr().getType() instanceof FloatingPointType and //getExpr为获取****转换的表达式;被转换的表达式属于浮点类型
c.getType() instanceof IntegralType //getType为获取表达式**被转换成**的类型;被转换成的类型为整形
select c

查找从浮点类型到整数类型的转换

catch_exception.ql

1
2
3
4
5
6
7
8
9
10
11
12
/**
* @description Finds places where we catch exceptions of type `parse_error`
*/

import cpp

from CatchBlock catch //CatchBlock,catch块,错误捕捉
// `stripType` converts `const parse_error &` to `parse_error`.
where catch.getParameter().getType().stripType().hasName("parse_error")
//getParameter,获取此“catch 块”引入的参数(如果有),即捕捉到的错误
//捕捉到的错误里有"parse_error"的字符串
select catch

查找我们捕获类型为 parse_error 的异常的地方,parse_error:拼写错误

constructor_call.ql

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* @description Finds places where we call `new MyClass(...)`
*/

import cpp

from NewExpr new, Constructor c //NewExpr,new表达式,例如new一个对象;Constryctor,c++构造函数
where
c = new.getInitializer().(ConstructorCall).getTarget() and
//getInitializer,对于 operator new,这将获取初始化已分配对象的调用或表达式(如果有)
c.getName() = "MyClass"
//对象调用为"myclass"
select new

查找我们调用new MyClass(...)的地方

derives_from_class.ql

1
2
3
4
5
6
7
8
9
10
11
/**
* @description Finds classes that derive from `std::exception`
*/

import cpp

from Class type //
where
type.getABaseClass+().hasName("exception") and //getABaseClass+获取基类(+号表至少获取一次,此处可以递归获取),基类为exception
type.getNamespace().getName() = "std" //命名空间为std
select type

查找从std::exception派生的类

emptyblock.ql

1
2
3
4
5
6
7
8
9
/**
* @description Finds empty block statements
*/

import cpp

from BlockStmt blk //块语句
where blk.getNumStmt() = 0 //getNumStmt,获取此块中主体语句的数量,为0则表示该块为空块
select blk

查找空块语句

emptythen.ql

1
2
3
4
5
6
7
8
9
/**
* @description Finds `if` statements where the `then` branch is an empty block statement
*/

import cpp

from IfStmt i //if语句块
where i.getThen().(BlockStmt).getNumStmt() = 0 //获取then语句块,强转为BlockStmt类型,判断该块是否为空
select i

查找if语句,其中then分支是一个空块语句

结果类似前一个,不再赘述

eq_true.ql

1
2
3
4
5
6
7
8
9
10
11
12
/**
* @description Finds tests like `==true`, `!=true`
*/

import cpp

from EqualityOperation eq, Expr trueExpr //EqualityOperation匹配相等运算,即“==”或“!=
where
trueExpr = eq.getAnOperand() and //获取操作数
trueExpr.getType() instanceof BoolType and //操作数为bool类型
trueExpr.getValue().toInt() = 1 //操作数的值为true
select eq

查找类似==true!=true

field_access.ql

1
2
3
4
5
6
7
8
9
10
11
12
/**
* @description Finds reads of `aDate` (defined on class `Order`)
*/

import cpp

from Field f, FieldAccess access //Field,C 结构成员或 C++ 非静态成员变量;FieldAccess,C/C++ 字段访问表达式
where
f.hasName("aDate") and
f.getDeclaringType().hasName("Order") and //获取声明此成员的类
f = access.getTarget()
select access

查找对aDate的读取(在类Order上定义)

function_call.ql

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* @description Finds calls to `std::map<...>::find()`
*/

import cpp

from FunctionCall call, Function fcn //函数调用点;函数
where
call.getTarget() = fcn and
fcn.getDeclaringType().getSimpleName() = "map" and //声明类为map
fcn.getDeclaringType().getNamespace().getName() = "std" and //命名空间为std
fcn.hasName("find") //调用的是find函数
select call

查找对std::map<...>::find()的调用

integer_literal.ql

1
2
3
4
5
6
7
8
9
10
11
/**
* @description Finds places where we use the integer literal `2`
*/

import cpp

from Literal literal //Literal提供用于对源代码中的文字进行建模的类,例如 0'c' 或“字符串”
where
literal.getType() instanceof IntType and //获取类型为整形
literal.getValue().toInt() = 2 //值为2
select literal

查找我们使用整数文字“2”的地方

mutualrecursion.ql

1
2
3
4
5
6
7
8
9
10
11
12
/**
* @description Finds pairs of functions that call each other
*/

import cpp

from Function m, Function n //函数m和函数n
where
exists(FunctionCall c | c.getEnclosingFunction() = m and c.getTarget() = n) and //获取函数调用,父函数为m,调用了n
exists(FunctionCall c | c.getEnclosingFunction() = n and c.getTarget() = m) and //获取函数调用,父函数为n,调用了m
m != n
select m, n

查找相互调用的函数对

override_method.ql

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* @description Finds methods that override `std::exception::what()`
*/

import cpp

from MemberFunction override, MemberFunction base //成员函数
where
base.getName() = "what" and //函数名为what的作为base函数
base.getDeclaringType().getName() = "exception" and //获取声明类为exception
base.getDeclaringType().getNamespace().getName() = "std" and //获取声明类的命名空间为std
override.overrides+(base) //获取重写函数(至少获取一次)
select override

查找覆盖std::exception::what()的方法

returnstatement.ql

1
2
3
4
5
6
7
8
9
/**
* @description Finds return statements that return `0`
*/

import cpp

from ReturnStmt r //return
where r.getExpr().(Literal).getValue().toInt() = 0 //getExpr获取表达式(Literal类型),获取值为0
select r

查找返回“0”的返回语句

singletonblock.ql

1
2
3
4
5
6
7
8
9
/**
* @description Finds block statements containing a single statement
*/

import cpp

from BlockStmt b //
where b.getNumStmt() = 1 //块的语句只有1
select b

查找包含单个语句的块语句

switchcase.ql

1
2
3
4
5
6
7
8
9
10
11
/**
* @description Finds switch statements with a missing enum constant case and no default case
*/

import cpp

from EnumSwitch es, EnumConstant ec //switch;枚举
where
ec = es.getAMissingCase() and //从枚举类型中获取一个常量,该常量在此“switch”语句中没有使用
not es.hasDefaultCase() //如果此“switch”语句具有“default case”语句,则保持不变;表示switch没有default语句
select es, ec

查找缺少枚举常量 case 且没有 default case 的 switch 语句

总结就是存在另外的情况但未匹配,也未加default处理的switch语句

ternaryconditional.ql

1
2
3
4
5
6
7
8
9
/**
* @description Finds conditional expressions of the form `... ? ... : ...` where the types of the resulting expressions differ
*/

import cpp

from ConditionalExpr e //ConditionalExpr为C/C++ 条件三元表达式
where e.getThen().getType() != e.getElse().getType() //获取此条件表达式的"then"表达式和"else"表达式,两者类型不同
select e

查找形式为... ? ... : ...的条件表达式其中结果表达式的类型不同

throw_exception.ql

1
2
3
4
5
6
7
8
9
/**
* @description Finds places where we throw `parse_error` or one of its sub-types
*/

import cpp

from ThrowExpr throw
where throw.getType().(Class).getABaseClass*().getName() = "parse_error"
select throw

查找我们抛出parse_error或其子类型之一的地方,很简单,不再赘述

todocomment.ql

1
2
3
4
5
6
7
8
9
/**
* @description Finds comments containing the word "TODO"
*/

import cpp

from Comment c //注释
where c.getContents().matches("%TODO%") //内容包含"TODO"
select c

查找包含单词“TODO”的注释

toomanyparams.ql

1
2
3
4
5
6
7
8
9
/**
* @description Finds functions or methods with more than 10 parameters
*/

import cpp

from Function fcn
where fcn.getNumberOfParameters() > 10 //获取函数的参数个数
select fcn

查找参数超过 10 个的函数或方法

unusedlocalvar.ql

1
2
3
4
5
6
7
8
9
10
11
/**
* @description Finds local variables that are not accessed
*/

import cpp

from LocalScopeVariable v //局部变量或函数参数
where
not v instanceof Parameter and
not exists(v.getAnAccess()) //变量v未被访问且不再catch throw中被使用
select v

查找未被访问的局部变量

unusedmethod.ql

1
2
3
4
5
6
7
8
9
10
11
12
/**
* @description Finds private non-virtual methods that are not accessed
*/

import cpp

from MemberFunction fcn //成员函数
where
fcn.isPrivate() and //为私有函数
not fcn.isVirtual() and //不是虚拟方法
not exists(FunctionCall call | fcn = call.getTarget()) //未被调用
select fcn.getDefinition() //获取函数定义

查找未访问的私有非虚拟方法

unusedparam.ql

1
2
3
4
5
6
7
8
9
/**
* @description Finds parameters that are not accessed
*/

import cpp

from Parameter p //参数p
where p.isNamed() and not exists(p.getAnAccess()) //有名称但未使用
select p

查找未被使用的参数

voidreturntype.ql

1
2
3
4
5
6
7
8
9
10
11
/**
* @description Finds const methods whose return type is `void`
*/

import cpp

from MemberFunction m //成员函数
where
m.hasSpecifier("const") and //hasSpecifier:如果此声明具有给定名称的说明符,则成立;查找const说明符
m.getType() instanceof VoidType //类型为void
select m

查找返回类型为void的 const 方法

volatilevariable.ql

1
2
3
4
5
6
7
8
9
/**
* @description Finds variables with a `volatile` modifier
*/

import cpp

from Variable f //变量
where f.isVolatile() //是volatile
select f

查找带有volatile修饰符的变量