Skip to content

Commit 236f413

Browse files
QL: Merge pull request #26 from github/builtins
Built in predicates
2 parents 28d2dae + 87e39c7 commit 236f413

5 files changed

Lines changed: 190 additions & 24 deletions

File tree

ql/src/codeql_ql/ast/Ast.qll

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,8 @@ class CharPred extends TCharPred, Predicate {
283283
or
284284
pred_name = directMember("getBody") and result = this.getBody()
285285
}
286+
287+
ClassType getDeclaringType() { result.getDeclaration() = getParent() }
286288
}
287289

288290
/**
@@ -600,7 +602,7 @@ class Call extends TCall, Expr {
600602
none() // overriden in sublcasses.
601603
}
602604

603-
Predicate getTarget() { resolveCall(this, result) }
605+
PredicateOrBuiltin getTarget() { resolveCall(this, result) }
604606

605607
override Type getType() { result = this.getTarget().getReturnType() }
606608

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
predicate isBuiltinClassless(string sig) {
2+
sig =
3+
[
4+
"predicate any()", "predicate none()", "predicate toUrl(string, int, int, int, string)",
5+
"predicate toUrl(string, int, int, int, int, string)"
6+
]
7+
}
8+
9+
predicate isBuiltinClassless(string ret, string name, string args) {
10+
exists(string sig, string re | re = "(\\w+) (\\w+)\\(([\\w, ]*)\\)" |
11+
isBuiltinClassless(sig) and
12+
ret = sig.regexpCapture(re, 1) and
13+
name = sig.regexpCapture(re, 2) and
14+
args = sig.regexpCapture(re, 3)
15+
)
16+
}
17+
18+
predicate isBuiltinMember(string sig) {
19+
sig =
20+
[
21+
"boolean boolean.booleanAnd(boolean)", "boolean boolean.booleanOr(boolean)",
22+
"boolean boolean.booleanXor(boolean)", "boolean boolean.booleanNot()",
23+
"string boolean.toString()", "float float.abs()", "float float.acos()", "float float.atan()",
24+
"int float.ceil()", "float float.copySign(float)", "float float.cos()", "float float.cosh()",
25+
"float float.exp()", "int float.floor()", "float float.log()", "float float.log(float)",
26+
"float float.log2()", "float float.log10()", "float float.maximum(float)",
27+
"float float.minimum(float)", "float float.nextAfter(float)", "float float.nextDown()",
28+
"float float.nextUp()", "float float.pow(float)", "float float.signum()", "float float.sin()",
29+
"float float.sinh()", "float float.sqrt()", "float float.tan()", "float float.tanh()",
30+
"string float.toString()", "float float.ulp()", "int int.abs()", "int int.bitAnd(int)",
31+
"int int.bitOr(int)", "int int.bitNot()", "int int.bitXor(int)", "int int.bitShiftLeft(int)",
32+
"int int.bitShiftRight(int)", "int int.bitShiftRightSigned(int)", "int int.gcd(int)",
33+
"string int.toString()", "string string.charAt(int)", "int string.indexOf(string)",
34+
"int string.indexOf(string, int, int)", "predicate string.isLowercase()",
35+
"predicate string.isUppercase()", "int string.length()", "predicate string.matches(string)",
36+
"string string.prefix(int)", "string regexpCapture(string, int)",
37+
"string regexpFind(string, int, int)", "predicate string.regexpMatch(string)",
38+
"string string.regexpReplaceAll(string, string)", "string string.replaceAll(string, string)",
39+
"string string.splitAt(string)", "string string.splitAt(string, int)",
40+
"string string.substring(int, int)", "string string.suffix(int)", "date string.toDate()",
41+
"float string.toFloat()", "int string.toInt()", "string string.toString()",
42+
"string string.toLowerCase()", "string string.toUpperCase()", "string string.trim()",
43+
"int date.daysTo(date)", "int date.getDay()", "int date.getHours()", "int date.getMinutes()",
44+
"int date.getMonth()", "int date.getSeconds()", "int date.getYear()",
45+
"string date.toString()", "string date.toISO()"
46+
]
47+
}
48+
49+
predicate isBuiltinMember(string qual, string ret, string name, string args) {
50+
exists(string sig, string re | re = "(\\w+) (\\w+)\\.(\\w+)\\(([\\w, ]*)\\)" |
51+
isBuiltinMember(sig) and
52+
ret = sig.regexpCapture(re, 1) and
53+
qual = sig.regexpCapture(re, 2) and
54+
name = sig.regexpCapture(re, 3) and
55+
args = sig.regexpCapture(re, 4)
56+
)
57+
}
58+
59+
bindingset[args]
60+
string getArgType(string args, int i) { result = args.splitAt(",", i).trim() }

ql/src/codeql_ql/ast/internal/Predicate.qll

Lines changed: 110 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import ql
2+
private import Builtins
23
private import codeql_ql.ast.internal.Module
34

45
private predicate definesPredicate(FileOrModule m, string name, ClasslessPredicate p, boolean public) {
@@ -38,7 +39,7 @@ predicate resolvePredicateExpr(PredicateExpr pe, ClasslessPredicate p) {
3839
)
3940
}
4041

41-
private predicate resolvePredicateCall(PredicateCall pc, Predicate p) {
42+
private predicate resolvePredicateCall(PredicateCall pc, PredicateOrBuiltin p) {
4243
exists(Class c, ClassType t |
4344
c = pc.getParent*() and
4445
t = c.getType() and
@@ -53,24 +54,125 @@ private predicate resolvePredicateCall(PredicateCall pc, Predicate p) {
5354
m = pc.getQualifier().getResolvedModule() and
5455
public = true
5556
|
56-
definesPredicate(m, pc.getPredicateName(), p, public) and
57-
count(p.getParameter(_)) = pc.getNumberOfArguments()
57+
definesPredicate(m, pc.getPredicateName(), p.getDeclaration(), public) and
58+
p.getArity() = pc.getNumberOfArguments()
5859
)
5960
}
6061

61-
private predicate resolveMemberCall(MemberCall mc, Predicate p) {
62-
exists(ClassType t |
62+
private predicate resolveMemberCall(MemberCall mc, PredicateOrBuiltin p) {
63+
exists(Type t |
6364
t = mc.getBase().getType() and
6465
p = t.getClassPredicate(mc.getMemberName(), mc.getNumberOfArguments())
6566
)
6667
}
6768

68-
predicate resolveCall(Call c, Predicate p) {
69+
predicate resolveCall(Call c, PredicateOrBuiltin p) {
6970
resolvePredicateCall(c, p)
7071
or
7172
resolveMemberCall(c, p)
7273
}
7374

75+
private newtype TPredOrBuiltin =
76+
TPred(Predicate p) or
77+
TBuiltinClassless(string ret, string name, string args) { isBuiltinClassless(ret, name, args) } or
78+
TBuiltinMember(string qual, string ret, string name, string args) {
79+
isBuiltinMember(qual, ret, name, args)
80+
}
81+
82+
class PredicateOrBuiltin extends TPredOrBuiltin {
83+
string getName() { none() }
84+
85+
string toString() { result = getName() }
86+
87+
predicate hasLocationInfo(
88+
string filepath, int startline, int startcolumn, int endline, int endcolumn
89+
) {
90+
if exists(getDeclaration())
91+
then
92+
getDeclaration()
93+
.getLocation()
94+
.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
95+
else (
96+
filepath = "" and
97+
startline = 0 and
98+
startcolumn = 0 and
99+
endline = 0 and
100+
endcolumn = 0
101+
)
102+
}
103+
104+
Predicate getDeclaration() { none() }
105+
106+
Type getDeclaringType() { none() }
107+
108+
Type getParameterType(int i) { none() }
109+
110+
Type getReturnType() { none() }
111+
112+
int getArity() { result = count(getParameterType(_)) }
113+
114+
predicate isPrivate() { none() }
115+
}
116+
117+
private class DefinedPredicate extends PredicateOrBuiltin, TPred {
118+
Predicate decl;
119+
120+
DefinedPredicate() { this = TPred(decl) }
121+
122+
override Predicate getDeclaration() { result = decl }
123+
124+
override string getName() { result = decl.getName() }
125+
126+
override Type getReturnType() { result = decl.getReturnType() }
127+
128+
override Type getParameterType(int i) { result = decl.getParameter(i).getType() }
129+
130+
override Type getDeclaringType() {
131+
result = decl.(ClassPredicate).getDeclaringType()
132+
or
133+
result = decl.(CharPred).getDeclaringType()
134+
}
135+
136+
override predicate isPrivate() {
137+
decl.(ClassPredicate).isPrivate() or decl.(ClassPredicate).isPrivate()
138+
}
139+
}
140+
141+
private class TBuiltin = TBuiltinClassless or TBuiltinMember;
142+
143+
class BuiltinPredicate extends PredicateOrBuiltin, TBuiltin { }
144+
145+
private class BuiltinClassless extends BuiltinPredicate, TBuiltinClassless {
146+
string name;
147+
string ret;
148+
string args;
149+
150+
BuiltinClassless() { this = TBuiltinClassless(ret, name, args) }
151+
152+
override string getName() { result = name }
153+
154+
override PrimitiveType getReturnType() { result.getName() = ret }
155+
156+
override PrimitiveType getParameterType(int i) { result.getName() = getArgType(args, i) }
157+
}
158+
159+
private class BuiltinMember extends BuiltinPredicate, TBuiltinMember {
160+
string name;
161+
string qual;
162+
string ret;
163+
string args;
164+
165+
BuiltinMember() { this = TBuiltinMember(qual, ret, name, args) }
166+
167+
override string getName() { result = name }
168+
169+
override PrimitiveType getReturnType() { result.getName() = ret }
170+
171+
override PrimitiveType getParameterType(int i) { result.getName() = getArgType(args, i) }
172+
173+
override PrimitiveType getDeclaringType() { result.getName() = qual }
174+
}
175+
74176
module PredConsistency {
75177
query predicate noResolvePredicateExpr(PredicateExpr pe) {
76178
not resolvePredicateExpr(pe, _) and
@@ -88,8 +190,8 @@ module PredConsistency {
88190
resolvePredicateExpr(pe, p)
89191
}
90192

91-
query predicate multipleResolveCall(Call call, int c, Predicate p) {
92-
c = strictcount(Predicate p0 | resolveCall(call, p0)) and
193+
query predicate multipleResolveCall(Call call, int c, PredicateOrBuiltin p) {
194+
c = strictcount(PredicateOrBuiltin p0 | resolveCall(call, p0)) and
93195
c > 1 and
94196
resolveCall(call, p)
95197
}

ql/src/codeql_ql/ast/internal/Type.qll

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import ql
22
private import codeql_ql.ast.internal.AstNodes as AstNodes
33
private import codeql_ql.ast.internal.TreeSitter
44
private import codeql_ql.ast.internal.Module
5+
private import codeql_ql.ast.internal.Predicate
56

67
private newtype TType =
78
TClass(Class c) { isActualClass(c) } or
@@ -59,6 +60,13 @@ class Type extends TType {
5960
endcolumn = 0
6061
)
6162
}
63+
64+
PredicateOrBuiltin getClassPredicate(string name, int arity) {
65+
result = classPredCandidate(this, name, arity) and
66+
not exists(PredicateOrBuiltin other | other = classPredCandidate(this, name, arity) |
67+
other.getDeclaringType().getASuperType+() = result.getDeclaringType()
68+
)
69+
}
6270
}
6371

6472
class ClassType extends Type, TClass {
@@ -78,13 +86,6 @@ class ClassType extends Type, TClass {
7886
result = super.getAnInternalSuperType()
7987
}
8088

81-
ClassPredicate getClassPredicate(string name, int arity) {
82-
result = classPredCandidate(this, name, arity) and
83-
not exists(ClassPredicate other | other = classPredCandidate(this, name, arity) |
84-
other.getDeclaringType().getASuperType+() = result.getDeclaringType()
85-
)
86-
}
87-
8889
VarDecl getField(string name) {
8990
result = fieldCandidate(this, name) and
9091
not exists(VarDecl other | other = fieldCandidate(this, name) |
@@ -93,26 +94,27 @@ class ClassType extends Type, TClass {
9394
}
9495
}
9596

96-
private ClassPredicate declaredPred(ClassType ty, string name, int arity) {
97-
result = ty.getDeclaration().getAClassPredicate() and
97+
private PredicateOrBuiltin declaredPred(Type ty, string name, int arity) {
98+
result.getDeclaringType() = ty and
9899
result.getName() = name and
99100
result.getArity() = arity
100101
}
101102

102-
private ClassPredicate classPredCandidate(ClassType ty, string name, int arity) {
103+
private PredicateOrBuiltin classPredCandidate(Type ty, string name, int arity) {
103104
result = declaredPred(ty, name, arity)
104105
or
105106
not exists(declaredPred(ty, name, arity)) and
106107
result = inherClassPredCandidate(ty, name, arity)
107108
}
108109

109-
private ClassPredicate inherClassPredCandidate(ClassType ty, string name, int arity) {
110-
result = classPredCandidate(ty.getASuperType(), name, arity) and
110+
private PredicateOrBuiltin inherClassPredCandidate(Type ty, string name, int arity) {
111+
result = classPredCandidate(ty.getAnInternalSuperType(), name, arity) and
111112
not result.isPrivate()
112113
}
113114

114115
predicate predOverrides(ClassPredicate sub, ClassPredicate sup) {
115-
sup = inherClassPredCandidate(sub.getDeclaringType(), sub.getName(), sub.getArity())
116+
sup =
117+
inherClassPredCandidate(sub.getDeclaringType(), sub.getName(), sub.getArity()).getDeclaration()
116118
}
117119

118120
private VarDecl declaredField(ClassType ty, string name) {
@@ -322,7 +324,7 @@ module TyConsistency {
322324

323325
query predicate exprNoType(Expr e) {
324326
not exists(e.getType()) and
325-
not exists(Predicate p |
327+
not exists(PredicateOrBuiltin p |
326328
p = e.(Call).getTarget() and
327329
not exists(p.getReturnType())
328330
) and

ql/src/ide-contextual-queries/Definitions.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ private predicate resolveVar(VarAccess va, VarDecl decl, string kind) {
4949
}
5050

5151
private predicate resolveCall(Call c, Predicate p, string kind) {
52-
p = c.getTarget() and
52+
p = c.getTarget().getDeclaration() and
5353
kind = "call"
5454
}
5555

0 commit comments

Comments
 (0)