mirror of
https://github.com/github/codeql.git
synced 2025-12-16 16:53:25 +01:00
177 lines
5.0 KiB
Plaintext
177 lines
5.0 KiB
Plaintext
/**
|
|
* Provides utility predicates for range analysis.
|
|
*/
|
|
overlay[local?]
|
|
module;
|
|
|
|
import java
|
|
private import SSA
|
|
private import semmle.code.java.controlflow.Guards
|
|
private import semmle.code.java.Constants
|
|
private import semmle.code.java.dataflow.RangeAnalysis
|
|
private import codeql.rangeanalysis.internal.RangeUtils
|
|
|
|
private module U = MakeUtils<Location, Sem, IntDelta>;
|
|
|
|
private predicate backEdge = U::backEdge/3;
|
|
|
|
predicate ssaRead = U::ssaRead/2;
|
|
|
|
predicate ssaUpdateStep = U::ssaUpdateStep/3;
|
|
|
|
predicate valueFlowStep = U::valueFlowStep/3;
|
|
|
|
predicate guardControlsSsaRead = U::guardControlsSsaRead/3;
|
|
|
|
predicate eqFlowCond = U::eqFlowCond/5;
|
|
|
|
/**
|
|
* Holds if `v` is an input to `phi` that is not along a back edge, and the
|
|
* only other input to `phi` is a `null` value.
|
|
*
|
|
* Note that the declared type of `phi` is `SsaVariable` instead of
|
|
* `SsaPhiDefinition` in order for the reflexive case of `nonNullSsaFwdStep*(..)` to
|
|
* have non-`SsaPhiDefinition` results.
|
|
*/
|
|
private predicate nonNullSsaFwdStep(SsaDefinition v, SsaDefinition phi) {
|
|
exists(SsaExplicitWrite vnull, SsaPhiDefinition phi0 | phi0 = phi |
|
|
2 = strictcount(phi0.getAnInput()) and
|
|
vnull = phi0.getAnInput() and
|
|
v = phi0.getAnInput() and
|
|
not backEdge(phi0, v, _) and
|
|
vnull != v and
|
|
vnull.getValue() instanceof NullLiteral
|
|
)
|
|
}
|
|
|
|
private predicate nonNullDefStep(Expr e1, Expr e2) {
|
|
exists(ConditionalExpr cond, boolean branch | cond = e2 |
|
|
cond.getBranchExpr(branch) = e1 and
|
|
cond.getBranchExpr(branch.booleanNot()) instanceof NullLiteral
|
|
)
|
|
}
|
|
|
|
/**
|
|
* Gets the definition of `v` provided that `v` is a non-null array with an
|
|
* explicit `ArrayCreationExpr` definition and that the definition does not go
|
|
* through a back edge.
|
|
*/
|
|
ArrayCreationExpr getArrayDef(SsaDefinition v) {
|
|
exists(Expr src |
|
|
v.(SsaExplicitWrite).getValue() = src and
|
|
nonNullDefStep*(result, src)
|
|
)
|
|
or
|
|
exists(SsaDefinition mid |
|
|
result = getArrayDef(mid) and
|
|
nonNullSsaFwdStep(mid, v)
|
|
)
|
|
}
|
|
|
|
/**
|
|
* Holds if `arrlen` is a read of an array `length` field on an array that, if
|
|
* it is non-null, is defined by `def` and that the definition can reach
|
|
* `arrlen` without going through a back edge.
|
|
*/
|
|
private predicate arrayLengthDef(FieldRead arrlen, ArrayCreationExpr def) {
|
|
exists(SsaDefinition arr |
|
|
arrlen.getField() instanceof ArrayLengthField and
|
|
arrlen.getQualifier() = arr.getARead() and
|
|
def = getArrayDef(arr)
|
|
)
|
|
}
|
|
|
|
/** An expression that always has the same integer value. */
|
|
pragma[nomagic]
|
|
private predicate constantIntegerExpr(Expr e, int val) {
|
|
e.(CompileTimeConstantExpr).getIntValue() = val
|
|
or
|
|
e.(LongLiteral).getValue().toInt() = val
|
|
or
|
|
exists(SsaExplicitWrite v, Expr src |
|
|
e = v.getARead() and
|
|
src = v.getValue() and
|
|
constantIntegerExpr(src, val)
|
|
)
|
|
or
|
|
exists(ArrayCreationExpr a |
|
|
arrayLengthDef(e, a) and
|
|
a.getFirstDimensionSize() = val
|
|
)
|
|
or
|
|
exists(Field a, FieldRead arrlen |
|
|
a.isFinal() and
|
|
a.getInitializer().(ArrayCreationExpr).getFirstDimensionSize() = val and
|
|
arrlen.getField() instanceof ArrayLengthField and
|
|
arrlen.getQualifier() = a.getAnAccess() and
|
|
e = arrlen
|
|
)
|
|
or
|
|
CalcConstants::calculateIntValue(e) = val
|
|
}
|
|
|
|
pragma[nomagic]
|
|
private predicate constantBooleanExpr(Expr e, boolean val) {
|
|
e.(CompileTimeConstantExpr).getBooleanValue() = val
|
|
or
|
|
exists(SsaExplicitWrite v, Expr src |
|
|
e = v.getARead() and
|
|
src = v.getValue() and
|
|
constantBooleanExpr(src, val)
|
|
)
|
|
or
|
|
CalcConstants::calculateBooleanValue(e) = val
|
|
}
|
|
|
|
pragma[nomagic]
|
|
private predicate constantStringExpr(Expr e, string val) {
|
|
e.(CompileTimeConstantExpr).getStringValue() = val
|
|
or
|
|
exists(SsaExplicitWrite v, Expr src |
|
|
e = v.getARead() and
|
|
src = v.getValue() and
|
|
constantStringExpr(src, val)
|
|
)
|
|
}
|
|
|
|
private boolean getBoolValue(Expr e) { constantBooleanExpr(e, result) }
|
|
|
|
private int getIntValue(Expr e) { constantIntegerExpr(e, result) }
|
|
|
|
private module CalcConstants = CalculateConstants<getBoolValue/1, getIntValue/1>;
|
|
|
|
/** An expression that always has the same integer value. */
|
|
class ConstantIntegerExpr extends Expr {
|
|
ConstantIntegerExpr() { constantIntegerExpr(this, _) }
|
|
|
|
/** Gets the integer value of this expression. */
|
|
int getIntValue() { constantIntegerExpr(this, result) }
|
|
}
|
|
|
|
/** An expression that always has the same boolean value. */
|
|
class ConstantBooleanExpr extends Expr {
|
|
ConstantBooleanExpr() { constantBooleanExpr(this, _) }
|
|
|
|
/** Gets the boolean value of this expression. */
|
|
boolean getBooleanValue() { constantBooleanExpr(this, result) }
|
|
}
|
|
|
|
/** An expression that always has the same string value. */
|
|
class ConstantStringExpr extends Expr {
|
|
ConstantStringExpr() { constantStringExpr(this, _) }
|
|
|
|
/** Get the string value of this expression. */
|
|
string getStringValue() { constantStringExpr(this, result) }
|
|
}
|
|
|
|
/**
|
|
* Holds if `e1 + delta` equals `e2`.
|
|
*/
|
|
predicate additionalValueFlowStep(Expr e2, Expr e1, int delta) {
|
|
exists(ArrayCreationExpr a |
|
|
arrayLengthDef(e2, a) and
|
|
a.getDimension(0) = e1 and
|
|
delta = 0
|
|
)
|
|
}
|