Skip to content

Commit 05f3934

Browse files
authored
Merge pull request #13251 from hvitved/ruby/call-graph-self-param
Ruby: Include both `self` parameters and SSA definitions in call graph construction
2 parents 818753e + 349de77 commit 05f3934

File tree

1 file changed

+38
-21
lines changed

1 file changed

+38
-21
lines changed

ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowDispatch.qll

Lines changed: 38 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,23 @@ private import FlowSummaryImplSpecific as FlowSummaryImplSpecific
99
private import codeql.ruby.dataflow.FlowSummary
1010
private import codeql.ruby.dataflow.SSA
1111

12+
/**
13+
* A `LocalSourceNode` for a `self` variable. This is either an implicit `self`
14+
* parameter or an implicit SSA entry definition.
15+
*/
16+
private class SelfLocalSourceNode extends DataFlow::LocalSourceNode {
17+
private SelfVariable self;
18+
19+
SelfLocalSourceNode() {
20+
self = this.(SelfParameterNode).getSelfVariable()
21+
or
22+
self = this.(SsaSelfDefinitionNode).getVariable()
23+
}
24+
25+
/** Gets the `self` variable. */
26+
SelfVariable getVariable() { result = self }
27+
}
28+
1229
newtype TReturnKind =
1330
TNormalReturnKind() or
1431
TBreakReturnKind() or
@@ -316,7 +333,7 @@ private predicate extendCall(DataFlow::ExprNode receiver, Module m) {
316333
exists(DataFlow::CallNode extendCall |
317334
extendCall.getMethodName() = "extend" and
318335
exists(DataFlow::LocalSourceNode sourceNode | sourceNode.flowsTo(extendCall.getArgument(_)) |
319-
selfInModule(sourceNode.(SsaSelfDefinitionNode).getVariable(), m) or
336+
selfInModule(sourceNode.(SelfLocalSourceNode).getVariable(), m) or
320337
m = resolveConstantReadAccess(sourceNode.asExpr().getExpr())
321338
) and
322339
receiver = extendCall.getReceiver()
@@ -329,7 +346,7 @@ private predicate extendCallModule(Module m, Module n) {
329346
exists(DataFlow::LocalSourceNode receiver, DataFlow::ExprNode e |
330347
receiver.flowsTo(e) and extendCall(e, n)
331348
|
332-
selfInModule(receiver.(SsaSelfDefinitionNode).getVariable(), m) or
349+
selfInModule(receiver.(SelfLocalSourceNode).getVariable(), m) or
333350
m = resolveConstantReadAccess(receiver.asExpr().getExpr())
334351
)
335352
}
@@ -502,12 +519,12 @@ private predicate isStandardNewCall(RelevantCall new, Module m, boolean exact) {
502519
exact = true
503520
or
504521
// `self.new` inside a module
505-
selfInModule(sourceNode.(SsaSelfDefinitionNode).getVariable(), m) and
522+
selfInModule(sourceNode.(SelfLocalSourceNode).getVariable(), m) and
506523
exact = true
507524
or
508525
// `self.new` inside a singleton method
509526
exists(MethodBase caller |
510-
selfInMethod(sourceNode.(SsaSelfDefinitionNode).getVariable(), caller, m) and
527+
selfInMethod(sourceNode.(SelfLocalSourceNode).getVariable(), caller, m) and
511528
singletonMethod(caller, _, _) and
512529
exact = false
513530
)
@@ -573,7 +590,7 @@ private predicate isInstance(DataFlow::Node n, Module tp, boolean exact) {
573590
// `self` reference in method or top-level (but not in module or singleton method,
574591
// where instance methods cannot be called; only singleton methods)
575592
n =
576-
any(SsaSelfDefinitionNode self |
593+
any(SelfLocalSourceNode self |
577594
exists(MethodBase m |
578595
selfInMethod(self.getVariable(), m, tp) and
579596
not m instanceof SingletonMethod and
@@ -607,10 +624,10 @@ private DataFlow::Node trackInstance(Module tp, boolean exact, TypeTracker t) {
607624
m = resolveConstantReadAccess(result.asExpr().getExpr())
608625
or
609626
// needed for e.g. `self.include`
610-
selfInModule(result.(SsaSelfDefinitionNode).getVariable(), m)
627+
selfInModule(result.(SelfLocalSourceNode).getVariable(), m)
611628
or
612629
// needed for e.g. `self.puts`
613-
selfInMethod(result.(SsaSelfDefinitionNode).getVariable(), any(SingletonMethod sm), m)
630+
selfInMethod(result.(SelfLocalSourceNode).getVariable(), any(SingletonMethod sm), m)
614631
)
615632
)
616633
or
@@ -970,7 +987,7 @@ private DataFlow::Node trackSingletonMethodOnInstance(MethodBase method, string
970987
/** Holds if a `self` access may be the receiver of `call` directly inside module `m`. */
971988
pragma[nomagic]
972989
private predicate selfInModuleFlowsToMethodCallReceiver(RelevantCall call, Module m, string method) {
973-
exists(SsaSelfDefinitionNode self |
990+
exists(SelfLocalSourceNode self |
974991
flowsToMethodCallReceiver(call, self, method) and
975992
selfInModule(self.getVariable(), m)
976993
)
@@ -984,7 +1001,7 @@ pragma[nomagic]
9841001
private predicate selfInSingletonMethodFlowsToMethodCallReceiver(
9851002
RelevantCall call, Module m, string method
9861003
) {
987-
exists(SsaSelfDefinitionNode self, MethodBase caller |
1004+
exists(SelfLocalSourceNode self, MethodBase caller |
9881005
flowsToMethodCallReceiver(call, self, method) and
9891006
selfInMethod(self.getVariable(), caller, m) and
9901007
singletonMethod(caller, _, _)
@@ -1062,10 +1079,13 @@ private CfgScope getTargetSingleton(RelevantCall call, string method) {
10621079
*/
10631080
pragma[nomagic]
10641081
private predicate argMustFlowToReceiver(
1065-
RelevantCall ctx, DataFlow::LocalSourceNode source, DataFlow::Node arg,
1066-
SsaDefinitionExtNode paramDef, RelevantCall call, Callable encl, string name
1082+
RelevantCall ctx, DataFlow::LocalSourceNode source, DataFlow::Node arg, RelevantCall call,
1083+
Callable encl, string name
10671084
) {
1068-
exists(ParameterNodeImpl p, ParameterPosition ppos, ArgumentPosition apos |
1085+
exists(
1086+
ParameterNodeImpl p, SsaDefinitionExtNode paramDef, ParameterPosition ppos,
1087+
ArgumentPosition apos
1088+
|
10691089
// the receiver of `call` references `p`
10701090
exists(DataFlow::Node receiver |
10711091
LocalFlow::localFlowSsaParamInput(p, paramDef) and
@@ -1106,7 +1126,7 @@ private predicate mayBenefitFromCallContextInitialize(
11061126
RelevantCall ctx, RelevantCall new, DataFlow::Node arg, Callable encl, Module tp, string name
11071127
) {
11081128
exists(DataFlow::LocalSourceNode source |
1109-
argMustFlowToReceiver(ctx, pragma[only_bind_into](source), arg, _, new, encl, "new") and
1129+
argMustFlowToReceiver(ctx, pragma[only_bind_into](source), arg, new, encl, "new") and
11101130
source = trackModuleAccess(tp) and
11111131
name = "initialize" and
11121132
exists(lookupMethod(tp, name))
@@ -1127,7 +1147,7 @@ private predicate mayBenefitFromCallContextInstance(
11271147
string name
11281148
) {
11291149
exists(DataFlow::LocalSourceNode source |
1130-
argMustFlowToReceiver(ctx, pragma[only_bind_into](source), arg, _, call, encl,
1150+
argMustFlowToReceiver(ctx, pragma[only_bind_into](source), arg, call, encl,
11311151
pragma[only_bind_into](name)) and
11321152
source = trackInstance(tp, exact) and
11331153
exists(lookupMethod(tp, pragma[only_bind_into](name)))
@@ -1148,7 +1168,7 @@ private predicate mayBenefitFromCallContextSingleton(
11481168
string name
11491169
) {
11501170
exists(DataFlow::LocalSourceNode source |
1151-
argMustFlowToReceiver(ctx, pragma[only_bind_into](source), pragma[only_bind_into](arg), _, call,
1171+
argMustFlowToReceiver(ctx, pragma[only_bind_into](source), pragma[only_bind_into](arg), call,
11521172
encl, pragma[only_bind_into](name)) and
11531173
exists(lookupSingletonMethod(tp, pragma[only_bind_into](name), exact))
11541174
|
@@ -1216,21 +1236,18 @@ DataFlowCallable viableImplInCallContext(DataFlowCall call, DataFlowCall ctx) {
12161236
or
12171237
// `ctx` cannot provide a type bound, and the receiver of the call is `self`;
12181238
// in this case, still apply an open-world assumption
1219-
exists(
1220-
RelevantCall call0, RelevantCall ctx0, DataFlow::Node arg, SsaSelfDefinitionNode self,
1221-
string name
1222-
|
1239+
exists(RelevantCall call0, RelevantCall ctx0, DataFlow::Node arg, string name |
12231240
call0 = call.asCall() and
12241241
ctx0 = ctx.asCall() and
1225-
argMustFlowToReceiver(ctx0, _, arg, self, call0, _, name) and
1242+
argMustFlowToReceiver(ctx0, _, arg, call0, _, name) and
12261243
not mayBenefitFromCallContextInitialize(ctx0, call0, arg, _, _, _) and
12271244
not mayBenefitFromCallContextInstance(ctx0, call0, arg, _, _, _, name) and
12281245
not mayBenefitFromCallContextSingleton(ctx0, call0, arg, _, _, _, name) and
12291246
result.asCallable() = viableSourceCallable(call0)
12301247
)
12311248
or
12321249
// library calls should always be able to resolve
1233-
argMustFlowToReceiver(ctx.asCall(), _, _, _, call.asCall(), _, _) and
1250+
argMustFlowToReceiver(ctx.asCall(), _, _, call.asCall(), _, _) and
12341251
result = viableLibraryCallable(call)
12351252
)
12361253
}

0 commit comments

Comments
 (0)