Skip to content

Commit f8b451a

Browse files
committed
get all calls to resolve to a unique predicate (within reason)
1 parent f08f02e commit f8b451a

File tree

5 files changed

+54
-18
lines changed

5 files changed

+54
-18
lines changed

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,8 @@ private module Cached {
229229
pragma[noinline]
230230
private predicate resolveModuleRefHelper(TypeRef me, ContainerOrModule enclosing, string name) {
231231
enclosing = getEnclosingModule(me).getEnclosing*() and
232-
name = [me.(ModuleExpr).getName(), me.(TypeExpr).getClassName()]
232+
name = [me.(ModuleExpr).getName(), me.(TypeExpr).getClassName()] and
233+
(not me instanceof ModuleExpr or not enclosing instanceof Folder_) // module expressions are not imports, so they can't resolve to a file (which is contained in a folder).
233234
}
234235
}
235236

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

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,23 @@ private module Cached {
8888
)
8989
}
9090

91+
/**
92+
* Holds if `mc` is a `this.method()` call to a predicate defined in the same class.
93+
* helps avoid spuriously resolving to predicates in super-classes.
94+
*/
95+
private predicate resolveSelfClassCalls(MemberCall mc, PredicateOrBuiltin p) {
96+
exists(Class c |
97+
mc.getBase() instanceof ThisAccess and
98+
c = mc.getEnclosingPredicate().getParent() and
99+
p = c.getClassPredicate(mc.getMemberName()) and
100+
p.getArity() = mc.getNumberOfArguments()
101+
)
102+
}
103+
91104
private predicate resolveMemberCall(MemberCall mc, PredicateOrBuiltin p) {
105+
resolveSelfClassCalls(mc, p)
106+
or
107+
not resolveSelfClassCalls(mc, _) and
92108
exists(Type t |
93109
t = mc.getBase().getType() and
94110
p = t.getClassPredicate(mc.getMemberName(), mc.getNumberOfArguments())
@@ -188,20 +204,20 @@ module PredConsistency {
188204
c > 1 and
189205
resolvePredicateExpr(pe, p)
190206
}
191-
// This can happen with parameterized modules
192-
/*
193-
* query predicate multipleResolveCall(Call call, int c, PredicateOrBuiltin p) {
194-
* c =
195-
* strictcount(PredicateOrBuiltin p0 |
196-
* resolveCall(call, p0) and
197-
* // aliases are expected to resolve to multiple.
198-
* not exists(p0.(ClasslessPredicate).getAlias()) and
199-
* // overridden predicates may have multiple targets
200-
* not p0.(ClassPredicate).isOverride()
201-
* ) and
202-
* c > 1 and
203-
* resolveCall(call, p)
204-
* }
205-
*/
206207

208+
query predicate multipleResolveCall(Call call, int c, PredicateOrBuiltin p) {
209+
c =
210+
strictcount(PredicateOrBuiltin p0 |
211+
resolveCall(call, p0) and
212+
// aliases are expected to resolve to multiple.
213+
not exists(p0.(ClasslessPredicate).getAlias()) and
214+
// overridden predicates may have multiple targets
215+
not p0.(ClassPredicate).isOverride() and
216+
not p0 instanceof Relation // <- DB relations resolve to both a relation and a predicate.
217+
) and
218+
c > 1 and
219+
resolveCall(call, p) and
220+
// parameterized modules are expected to resolve to multiple.
221+
not exists(Predicate sig | not exists(sig.getBody()) and resolveCall(call, sig))
207222
}
223+
}

ql/ql/src/queries/diagnostics/EmptyConsistencies.ql

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ where
2222
or
2323
PredConsistency::noResolvePredicateExpr(node) and msg = "PredConsistency::noResolvePredicateExpr"
2424
or
25+
PredConsistency::multipleResolveCall(node, _, _) and msg = "PredConsistency::multipleResolveCall"
26+
or
2527
TypeConsistency::exprNoType(node) and msg = "TypeConsistency::exprNoType"
2628
or
2729
TypeConsistency::varDefNoType(node) and msg = "TypeConsistency::varDefNoType"

ql/ql/test/callgraph/MultiResolve.qll

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,19 @@ class Super2 extends int {
4040
class Sub extends Super1, Super2 {
4141
override predicate foo() { Super1.super.foo() } // <- should resolve to Super1::foo()
4242
}
43+
44+
module Foo {
45+
predicate foo() { any() }
46+
}
47+
48+
predicate test() {
49+
Foo::foo() // <- should resolve to `foo` from the module above, and not from the `Foo.qll` file.
50+
}
51+
52+
class Sub2 extends Super1, Super2 {
53+
override predicate foo() { Super2.super.foo() } // <- should resolve to Super2::foo()
54+
55+
predicate test() {
56+
this.foo() // <- should resolve to only the above `foo` predicate, but currently it resolves to that, and all the overrides [INCONSISTENCY]
57+
}
58+
}

ql/ql/test/callgraph/callgraph.expected

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,11 @@ getTarget
1818
| MultiResolve.qll:14:25:14:35 | PredicateCall | MultiResolve.qll:12:1:12:24 | ClasslessPredicate myFoo |
1919
| MultiResolve.qll:23:7:23:18 | PredicateCall | MultiResolve.qll:17:3:17:27 | ClasslessPredicate bar |
2020
| MultiResolve.qll:41:30:41:47 | MemberCall | MultiResolve.qll:31:3:31:27 | ClassPredicate foo |
21+
| MultiResolve.qll:49:3:49:12 | PredicateCall | MultiResolve.qll:45:3:45:27 | ClasslessPredicate foo |
22+
| MultiResolve.qll:53:30:53:47 | MemberCall | MultiResolve.qll:37:3:37:28 | ClassPredicate foo |
23+
| MultiResolve.qll:56:5:56:14 | MemberCall | MultiResolve.qll:53:12:53:49 | ClassPredicate foo |
2124
| Overrides.qll:8:30:8:39 | MemberCall | Overrides.qll:6:3:6:29 | ClassPredicate bar |
22-
| Overrides.qll:16:39:16:48 | MemberCall | Overrides.qll:6:3:6:29 | ClassPredicate bar |
2325
| Overrides.qll:16:39:16:48 | MemberCall | Overrides.qll:14:12:14:43 | ClassPredicate bar |
24-
| Overrides.qll:24:39:24:48 | MemberCall | Overrides.qll:6:3:6:29 | ClassPredicate bar |
2526
| Overrides.qll:24:39:24:48 | MemberCall | Overrides.qll:22:12:22:44 | ClassPredicate bar |
2627
| Overrides.qll:28:3:28:9 | MemberCall | Overrides.qll:6:3:6:29 | ClassPredicate bar |
2728
| Overrides.qll:29:3:29:10 | MemberCall | Overrides.qll:8:3:8:41 | ClassPredicate baz |

0 commit comments

Comments
 (0)