Resolve instance method calls

This commit is contained in:
Arthur Baars
2021-04-29 12:39:09 +02:00
parent 3c80b32ba0
commit b13bae6a4e
2 changed files with 61 additions and 4 deletions

View File

@@ -110,7 +110,7 @@ private predicate isDefinedConstant(string qualifiedModuleName) {
* definition is a Namespace then it is returned, if it's a constant assignment then
* the right-hand side of the assignment is resolved.
*/
private TResolved resolveScopeExpr(ConstantReadAccess r) {
TResolved resolveScopeExpr(ConstantReadAccess r) {
exists(string qname |
qname =
min(string qn, int p |

View File

@@ -1,6 +1,9 @@
private import ruby
private import codeql_ruby.CFG
private import DataFlowPrivate
private import codeql_ruby.typetracking.TypeTracker
private import codeql_ruby.dataflow.internal.DataFlowPublic as DataFlow
private import codeql_ruby.ast.internal.Module
newtype TReturnKind =
TNormalReturnKind() or
@@ -42,12 +45,66 @@ class DataFlowCall extends CfgNodes::ExprNodes::CallCfgNode {
DataFlowCallable getEnclosingCallable() { result = this.getScope() }
DataFlowCallable getTarget() {
// TODO: this is a placeholder that finds a method with the same name, iff it's uniquely named.
result =
unique(DataFlowCallable c | c.(Method).getName() = this.getNode().(MethodCall).getMethodName())
exists(MethodCall mcall, Module tp |
mcall = this.getExpr() and
result = lookupMethod(tp, mcall.getMethodName())
|
exists(DataFlow::Node nodeTo |
nodeTo.asExpr() = this.getReceiver() and
trackInstance(tp).flowsTo(nodeTo)
)
)
}
}
private DataFlow::LocalSourceNode trackInstance(Module tp, TypeTracker t) {
t.start() and
(
exists(CfgNodes::ExprNodes::CallCfgNode call, DataFlow::Node nodeTo |
call.getExpr().(MethodCall).getMethodName() = "new" and
nodeTo.asExpr() = call.getReceiver() and
trackModule(tp).flowsTo(nodeTo) and
result.asExpr() = call
)
or
// `self` in method
exists(Self self, Method enclosing |
self = result.asExpr().getExpr() and
enclosing = self.getEnclosingMethod() and
tp = enclosing.getEnclosingModule().getModule() and
not self.getEnclosingModule().getEnclosingMethod() = enclosing
)
)
or
exists(TypeTracker t2 | result = trackInstance(tp, t2).track(t2, t))
}
private DataFlow::LocalSourceNode trackInstance(Module tp) {
result = trackInstance(tp, TypeTracker::end())
}
private DataFlow::LocalSourceNode trackModule(Module tp, TypeTracker t) {
t.start() and
(
// ConstantReadAccess to Module
resolveScopeExpr(result.asExpr().getExpr()) = tp
or
// `self` reference to Module
exists(Self self, ModuleBase enclosing |
self = result.asExpr().getExpr() and
enclosing = self.getEnclosingModule() and
tp = enclosing.getModule() and
not self.getEnclosingMethod().getEnclosingModule() = enclosing
)
)
or
exists(TypeTracker t2 | result = trackModule(tp, t2).track(t2, t))
}
private DataFlow::LocalSourceNode trackModule(Module tp) {
result = trackModule(tp, TypeTracker::end())
}
/** Gets a viable run-time target for the call `call`. */
DataFlowCallable viableCallable(DataFlowCall call) { none() }