示例代码:
void foo(long l) {
for(int i=0; i<l; i++) {
// do something
}
}
该代码存在溢出风险,当l > 2^31-1(int类型的最大值)时,程序会进入死循环。那么,怎么用codeQL找到这种溢出风险点呢?
初始查询
import java
from LTExpr expr
where expr.getLeftOperand().getType().hasName("int") and
expr.getRightOperand().getType().hasName("long")
select expr
其中,LTExpr
表示less than expression。
修正版,增加loop限制,以及参数为非常量(如果有一个参数为常量的话,不会导致真正的bug):
import java
from LTExpr expr
where expr.getLeftOperand().getType().hasName("int") and
expr.getRightOperand().getType().hasName("long") and
exists(LoopStmt l | l.getCondition().getAChildExpr*() = expr) and
not expr.getAnOperand().isCompileTimeConstant()
select expr
Generalizing the query
不仅int和long比较会出错,所有的窄类型与宽类型比较都会出错。不仅less than有问题,所有的 equal to、great than也可能会有问题,因此,需要将这个问题一般化。
一般化的查询如下:
import java
// Return the width (in bits) of a given integral type
int width(PrimitiveType pt) {
(pt.hasName("byte") and result=8) or
(pt.hasName("short") and result=16) or
(pt.hasName("char") and result=16) or
(pt.hasName("int") and result=32) or
(pt.hasName("long") and result=64)
}
// Find any comparison where the width of the type on the smaller end of
// the comparison is less than the width of the type on the greater end
abstract class OverflowProneComparison extends ComparisonExpr {
Expr getLesserOperand() { none() }
Expr getGreaterOperand() { none() }
}
// Return `<=` and `<` comparisons
class LTOverflowProneComparison extends OverflowProneComparison {
LTOverflowProneComparison() {
(this instanceof LEExpr or this instanceof LTExpr) and
width(this.getLeftOperand().getType()) < width(this.getRightOperand().getType())
}
}
// Return `>=` and `>` comparisons
class GTOverflowProneComparison extends OverflowProneComparison {
GTOverflowProneComparison() {
(this instanceof GEExpr or this instanceof GTExpr) and
width(this.getRightOperand().getType()) < width(this.getLeftOperand().getType())
}
}
from OverflowProneComparison expr
where exists(LoopStmt l | l.getCondition().getAChildExpr*() = expr) and
not expr.getAnOperand().isCompileTimeConstant()
select expr
References
https://help.semmle.com/QL/learn-ql/java/expressions-statements.html