mirror of
https://github.com/github/codeql.git
synced 2026-02-07 18:51:06 +01:00
Support builtin predicates
This commit is contained in:
@@ -283,6 +283,8 @@ class CharPred extends TCharPred, Predicate {
|
||||
or
|
||||
pred_name = directMember("getBody") and result = this.getBody()
|
||||
}
|
||||
|
||||
ClassType getDeclaringType() { result.getDeclaration() = getParent() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -600,7 +602,7 @@ class Call extends TCall, Expr {
|
||||
none() // overriden in sublcasses.
|
||||
}
|
||||
|
||||
Predicate getTarget() { resolveCall(this, result) }
|
||||
PredicateOrBuiltin getTarget() { resolveCall(this, result) }
|
||||
|
||||
override Type getType() { result = this.getTarget().getReturnType() }
|
||||
|
||||
|
||||
60
ql/src/codeql_ql/ast/internal/Builtins.qll
Normal file
60
ql/src/codeql_ql/ast/internal/Builtins.qll
Normal file
@@ -0,0 +1,60 @@
|
||||
predicate isBuiltinClassless(string sig) {
|
||||
sig =
|
||||
[
|
||||
"predicate any()", "predicate none()", "predicate toUrl(string, int, int, int, string)",
|
||||
"predicate toUrl(string, int, int, int, int, string)"
|
||||
]
|
||||
}
|
||||
|
||||
predicate isBuiltinClassless(string ret, string name, string args) {
|
||||
exists(string sig, string re | re = "(\\w+) (\\w+)\\(([\\w, ]*)\\)" |
|
||||
isBuiltinClassless(sig) and
|
||||
ret = sig.regexpCapture(re, 1) and
|
||||
name = sig.regexpCapture(re, 2) and
|
||||
args = sig.regexpCapture(re, 3)
|
||||
)
|
||||
}
|
||||
|
||||
predicate isBuiltinMember(string sig) {
|
||||
sig =
|
||||
[
|
||||
"boolean boolean.booleanAnd(boolean)", "boolean boolean.booleanOr(boolean)",
|
||||
"boolean boolean.booleanXor(boolean)", "boolean boolean.booleanNot()",
|
||||
"string boolean.toString()", "float float.abs()", "float float.acos()", "float float.atan()",
|
||||
"int float.ceil()", "float float.copySign(float)", "float float.cos()", "float float.cosh()",
|
||||
"float float.exp()", "int float.floor()", "float float.log()", "float float.log(float)",
|
||||
"float float.log2()", "float float.log10()", "float float.maximum(float)",
|
||||
"float float.minimum(float)", "float float.nextAfter(float)", "float float.nextDown()",
|
||||
"float float.nextUp()", "float float.pow(float)", "float float.signum()", "float float.sin()",
|
||||
"float float.sinh()", "float float.sqrt()", "float float.tan()", "float float.tanh()",
|
||||
"string float.toString()", "float float.ulp()", "int int.abs()", "int int.bitAnd(int)",
|
||||
"int int.bitOr(int)", "int int.bitNot()", "int int.bitXor(int)", "int int.bitShiftLeft(int)",
|
||||
"int int.bitShiftRight(int)", "int int.bitShiftRightSigned(int)", "int int.gcd(int)",
|
||||
"string int.toString()", "string string.charAt(int)", "int string.indexOf(string)",
|
||||
"int string.indexOf(string, int, int)", "predicate string.isLowercase()",
|
||||
"predicate string.isUppercase()", "int string.length()", "predicate string.matches(string)",
|
||||
"string string.prefix(int)", "string regexpCapture(string, int)",
|
||||
"string regexpFind(string, int, int)", "predicate string.regexpMatch(string)",
|
||||
"string string.regexpReplaceAll(string, string)", "string string.replaceAll(string, string)",
|
||||
"string string.splitAt(string)", "string string.splitAt(string, int)",
|
||||
"string string.substring(int, int)", "string string.suffix(int)", "date string.toDate()",
|
||||
"float string.toFloat()", "int string.toInt()", "string string.toString()",
|
||||
"string string.toLowerCase()", "string string.toUpperCase()", "string string.trim()",
|
||||
"int date.daysTo(date)", "int date.getDay()", "int date.getHours()", "int date.getMinutes()",
|
||||
"int date.getMonth()", "int date.getSeconds()", "int date.getYear()",
|
||||
"string date.toString()", "string date.toISO()"
|
||||
]
|
||||
}
|
||||
|
||||
predicate isBuiltinMember(string qual, string ret, string name, string args) {
|
||||
exists(string sig, string re | re = "(\\w+) (\\w+)\\.(\\w+)\\(([\\w, ]*)\\)" |
|
||||
isBuiltinMember(sig) and
|
||||
ret = sig.regexpCapture(re, 1) and
|
||||
qual = sig.regexpCapture(re, 2) and
|
||||
name = sig.regexpCapture(re, 3) and
|
||||
args = sig.regexpCapture(re, 4)
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[args]
|
||||
string getArgType(string args, int i) { result = args.splitAt(",", i).trim() }
|
||||
@@ -1,4 +1,5 @@
|
||||
import ql
|
||||
private import Builtins
|
||||
private import codeql_ql.ast.internal.Module
|
||||
|
||||
private predicate definesPredicate(FileOrModule m, string name, ClasslessPredicate p, boolean public) {
|
||||
@@ -38,7 +39,7 @@ predicate resolvePredicateExpr(PredicateExpr pe, ClasslessPredicate p) {
|
||||
)
|
||||
}
|
||||
|
||||
private predicate resolvePredicateCall(PredicateCall pc, Predicate p) {
|
||||
private predicate resolvePredicateCall(PredicateCall pc, PredicateOrBuiltin p) {
|
||||
exists(Class c, ClassType t |
|
||||
c = pc.getParent*() and
|
||||
t = c.getType() and
|
||||
@@ -53,24 +54,125 @@ private predicate resolvePredicateCall(PredicateCall pc, Predicate p) {
|
||||
m = pc.getQualifier().getResolvedModule() and
|
||||
public = true
|
||||
|
|
||||
definesPredicate(m, pc.getPredicateName(), p, public) and
|
||||
count(p.getParameter(_)) = pc.getNumberOfArguments()
|
||||
definesPredicate(m, pc.getPredicateName(), p.getDeclaration(), public) and
|
||||
p.getArity() = pc.getNumberOfArguments()
|
||||
)
|
||||
}
|
||||
|
||||
private predicate resolveMemberCall(MemberCall mc, Predicate p) {
|
||||
exists(ClassType t |
|
||||
private predicate resolveMemberCall(MemberCall mc, PredicateOrBuiltin p) {
|
||||
exists(Type t |
|
||||
t = mc.getBase().getType() and
|
||||
p = t.getClassPredicate(mc.getMemberName(), mc.getNumberOfArguments())
|
||||
)
|
||||
}
|
||||
|
||||
predicate resolveCall(Call c, Predicate p) {
|
||||
predicate resolveCall(Call c, PredicateOrBuiltin p) {
|
||||
resolvePredicateCall(c, p)
|
||||
or
|
||||
resolveMemberCall(c, p)
|
||||
}
|
||||
|
||||
private newtype TPredOrBuiltin =
|
||||
TPred(Predicate p) or
|
||||
TBuiltinClassless(string ret, string name, string args) { isBuiltinClassless(ret, name, args) } or
|
||||
TBuiltinMember(string qual, string ret, string name, string args) {
|
||||
isBuiltinMember(qual, ret, name, args)
|
||||
}
|
||||
|
||||
class PredicateOrBuiltin extends TPredOrBuiltin {
|
||||
string getName() { none() }
|
||||
|
||||
string toString() { result = getName() }
|
||||
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
if exists(getDeclaration())
|
||||
then
|
||||
getDeclaration()
|
||||
.getLocation()
|
||||
.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
else (
|
||||
filepath = "" and
|
||||
startline = 0 and
|
||||
startcolumn = 0 and
|
||||
endline = 0 and
|
||||
endcolumn = 0
|
||||
)
|
||||
}
|
||||
|
||||
Predicate getDeclaration() { none() }
|
||||
|
||||
Type getDeclaringType() { none() }
|
||||
|
||||
Type getParameterType(int i) { none() }
|
||||
|
||||
Type getReturnType() { none() }
|
||||
|
||||
int getArity() { result = count(getParameterType(_)) }
|
||||
|
||||
predicate isPrivate() { none() }
|
||||
}
|
||||
|
||||
private class DefinedPredicate extends PredicateOrBuiltin, TPred {
|
||||
Predicate decl;
|
||||
|
||||
DefinedPredicate() { this = TPred(decl) }
|
||||
|
||||
override Predicate getDeclaration() { result = decl }
|
||||
|
||||
override string getName() { result = decl.getName() }
|
||||
|
||||
override Type getReturnType() { result = decl.getReturnType() }
|
||||
|
||||
override Type getParameterType(int i) { result = decl.getParameter(i).getType() }
|
||||
|
||||
override Type getDeclaringType() {
|
||||
result = decl.(ClassPredicate).getDeclaringType()
|
||||
or
|
||||
result = decl.(CharPred).getDeclaringType()
|
||||
}
|
||||
|
||||
override predicate isPrivate() {
|
||||
decl.(ClassPredicate).isPrivate() or decl.(ClassPredicate).isPrivate()
|
||||
}
|
||||
}
|
||||
|
||||
private class TBuiltin = TBuiltinClassless or TBuiltinMember;
|
||||
|
||||
class BuiltinPredicate extends PredicateOrBuiltin, TBuiltin { }
|
||||
|
||||
private class BuiltinClassless extends BuiltinPredicate, TBuiltinClassless {
|
||||
string name;
|
||||
string ret;
|
||||
string args;
|
||||
|
||||
BuiltinClassless() { this = TBuiltinClassless(ret, name, args) }
|
||||
|
||||
override string getName() { result = name }
|
||||
|
||||
override PrimitiveType getReturnType() { result.getName() = ret }
|
||||
|
||||
override PrimitiveType getParameterType(int i) { result.getName() = getArgType(args, i) }
|
||||
}
|
||||
|
||||
private class BuiltinMember extends BuiltinPredicate, TBuiltinMember {
|
||||
string name;
|
||||
string qual;
|
||||
string ret;
|
||||
string args;
|
||||
|
||||
BuiltinMember() { this = TBuiltinMember(qual, ret, name, args) }
|
||||
|
||||
override string getName() { result = name }
|
||||
|
||||
override PrimitiveType getReturnType() { result.getName() = ret }
|
||||
|
||||
override PrimitiveType getParameterType(int i) { result.getName() = getArgType(args, i) }
|
||||
|
||||
override PrimitiveType getDeclaringType() { result.getName() = qual }
|
||||
}
|
||||
|
||||
module PredConsistency {
|
||||
query predicate noResolvePredicateExpr(PredicateExpr pe) {
|
||||
not resolvePredicateExpr(pe, _) and
|
||||
@@ -88,8 +190,8 @@ module PredConsistency {
|
||||
resolvePredicateExpr(pe, p)
|
||||
}
|
||||
|
||||
query predicate multipleResolveCall(Call call, int c, Predicate p) {
|
||||
c = strictcount(Predicate p0 | resolveCall(call, p0)) and
|
||||
query predicate multipleResolveCall(Call call, int c, PredicateOrBuiltin p) {
|
||||
c = strictcount(PredicateOrBuiltin p0 | resolveCall(call, p0)) and
|
||||
c > 1 and
|
||||
resolveCall(call, p)
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import ql
|
||||
private import codeql_ql.ast.internal.AstNodes as AstNodes
|
||||
private import codeql_ql.ast.internal.TreeSitter
|
||||
private import codeql_ql.ast.internal.Module
|
||||
private import codeql_ql.ast.internal.Predicate
|
||||
|
||||
private newtype TType =
|
||||
TClass(Class c) { isActualClass(c) } or
|
||||
@@ -59,6 +60,13 @@ class Type extends TType {
|
||||
endcolumn = 0
|
||||
)
|
||||
}
|
||||
|
||||
PredicateOrBuiltin getClassPredicate(string name, int arity) {
|
||||
result = classPredCandidate(this, name, arity) and
|
||||
not exists(PredicateOrBuiltin other | other = classPredCandidate(this, name, arity) |
|
||||
other.getDeclaringType().getASuperType+() = result.getDeclaringType()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class ClassType extends Type, TClass {
|
||||
@@ -78,13 +86,6 @@ class ClassType extends Type, TClass {
|
||||
result = super.getAnInternalSuperType()
|
||||
}
|
||||
|
||||
ClassPredicate getClassPredicate(string name, int arity) {
|
||||
result = classPredCandidate(this, name, arity) and
|
||||
not exists(ClassPredicate other | other = classPredCandidate(this, name, arity) |
|
||||
other.getDeclaringType().getASuperType+() = result.getDeclaringType()
|
||||
)
|
||||
}
|
||||
|
||||
VarDecl getField(string name) {
|
||||
result = fieldCandidate(this, name) and
|
||||
not exists(VarDecl other | other = fieldCandidate(this, name) |
|
||||
@@ -93,26 +94,27 @@ class ClassType extends Type, TClass {
|
||||
}
|
||||
}
|
||||
|
||||
private ClassPredicate declaredPred(ClassType ty, string name, int arity) {
|
||||
result = ty.getDeclaration().getAClassPredicate() and
|
||||
private PredicateOrBuiltin declaredPred(Type ty, string name, int arity) {
|
||||
result.getDeclaringType() = ty and
|
||||
result.getName() = name and
|
||||
result.getArity() = arity
|
||||
}
|
||||
|
||||
private ClassPredicate classPredCandidate(ClassType ty, string name, int arity) {
|
||||
private PredicateOrBuiltin classPredCandidate(Type ty, string name, int arity) {
|
||||
result = declaredPred(ty, name, arity)
|
||||
or
|
||||
not exists(declaredPred(ty, name, arity)) and
|
||||
result = inherClassPredCandidate(ty, name, arity)
|
||||
}
|
||||
|
||||
private ClassPredicate inherClassPredCandidate(ClassType ty, string name, int arity) {
|
||||
result = classPredCandidate(ty.getASuperType(), name, arity) and
|
||||
private PredicateOrBuiltin inherClassPredCandidate(Type ty, string name, int arity) {
|
||||
result = classPredCandidate(ty.getAnInternalSuperType(), name, arity) and
|
||||
not result.isPrivate()
|
||||
}
|
||||
|
||||
predicate predOverrides(ClassPredicate sub, ClassPredicate sup) {
|
||||
sup = inherClassPredCandidate(sub.getDeclaringType(), sub.getName(), sub.getArity())
|
||||
sup =
|
||||
inherClassPredCandidate(sub.getDeclaringType(), sub.getName(), sub.getArity()).getDeclaration()
|
||||
}
|
||||
|
||||
private VarDecl declaredField(ClassType ty, string name) {
|
||||
@@ -322,7 +324,7 @@ module TyConsistency {
|
||||
|
||||
query predicate exprNoType(Expr e) {
|
||||
not exists(e.getType()) and
|
||||
not exists(Predicate p |
|
||||
not exists(PredicateOrBuiltin p |
|
||||
p = e.(Call).getTarget() and
|
||||
not exists(p.getReturnType())
|
||||
) and
|
||||
|
||||
@@ -49,7 +49,7 @@ private predicate resolveVar(VarAccess va, VarDecl decl, string kind) {
|
||||
}
|
||||
|
||||
private predicate resolveCall(Call c, Predicate p, string kind) {
|
||||
p = c.getTarget() and
|
||||
p = c.getTarget().getDeclaration() and
|
||||
kind = "call"
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user