Support builtin predicates

This commit is contained in:
Joe Farebrother
2021-05-28 12:28:07 +01:00
parent 671628484b
commit 3945dbfa54
5 changed files with 190 additions and 24 deletions

View File

@@ -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() }

View 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() }

View File

@@ -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)
}

View File

@@ -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

View File

@@ -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"
}