Ruby: Prevent flow into self in trackBlock

This commit is contained in:
Tom Hvitved
2023-04-24 11:28:09 +02:00
parent bfbbb5277d
commit b94289fde1
2 changed files with 26 additions and 16 deletions

View File

@@ -191,13 +191,7 @@ private predicate moduleFlowsToMethodCallReceiver(RelevantCall call, Module m, s
flowsToMethodCallReceiver(call, trackModuleAccess(m), method)
}
private Block yieldCall(RelevantCall call) {
call.getExpr() instanceof YieldCall and
exists(BlockParameterNode node |
node = trackBlock(result) and
node.getMethod() = call.getExpr().getEnclosingMethod()
)
}
private Block blockCall(RelevantCall call) { lambdaSourceCall(call, _, trackBlock(result)) }
pragma[nomagic]
private predicate superCall(RelevantCall call, Module cls, string method) {
@@ -297,7 +291,7 @@ predicate isUserDefinedNew(SingletonMethod new) {
private Callable viableSourceCallableNonInit(RelevantCall call) {
result = getTarget(call) and
not call.getExpr() instanceof YieldCall // handled by `lambdaCreation`/`lambdaCall`
not result = blockCall(call) // handled by `lambdaCreation`/`lambdaCall`
}
private Callable viableSourceCallableInit(RelevantCall call) { result = getInitializeTarget(call) }
@@ -394,7 +388,7 @@ private module Cached {
result = lookupMethod(cls.getAnImmediateAncestor(), method)
)
or
result = yieldCall(call)
result = blockCall(call)
}
/** Gets a viable run-time target for the call `call`. */
@@ -700,13 +694,19 @@ private DataFlow::LocalSourceNode trackBlock(Block block, TypeTracker t) {
t.start() and result.asExpr().getExpr() = block
or
exists(TypeTracker t2, StepSummary summary |
result = trackBlockRec(block, t2, summary) and t = t2.append(summary)
result = trackBlockRec(block, t2, summary) and
t = t2.append(summary)
)
}
/**
* We exclude steps into `self` parameters, which may happen when the code
* base contains implementations of `call`.
*/
pragma[nomagic]
private DataFlow::LocalSourceNode trackBlockRec(Block block, TypeTracker t, StepSummary summary) {
StepSummary::step(trackBlock(block, t), result, summary)
StepSummary::step(trackBlock(block, t), result, summary) and
not result instanceof SelfParameterNode
}
pragma[nomagic]

View File

@@ -1377,18 +1377,28 @@ predicate lambdaCreation(Node creation, LambdaCallKind kind, DataFlowCallable c)
)
}
/** Holds if `call` is a lambda call of kind `kind` where `receiver` is the lambda expression. */
predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) {
/**
* Holds if `call` is a from-source lambda call of kind `kind` where `receiver`
* is the lambda expression.
*/
predicate lambdaSourceCall(CfgNodes::ExprNodes::CallCfgNode call, LambdaCallKind kind, Node receiver) {
kind = TYieldCallKind() and
receiver.(BlockParameterNode).getMethod() =
call.asCall().getExpr().(YieldCall).getEnclosingMethod()
receiver.(BlockParameterNode).getMethod() = call.getExpr().(YieldCall).getEnclosingMethod()
or
kind = TLambdaCallKind() and
call.asCall() =
call =
any(CfgNodes::ExprNodes::MethodCallCfgNode mc |
receiver.asExpr() = mc.getReceiver() and
mc.getExpr().getMethodName() = "call"
)
}
/**
* Holds if `call` is a (from-source or from-summary) lambda call of kind `kind`
* where `receiver` is the lambda expression.
*/
predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) {
lambdaSourceCall(call.asCall(), kind, receiver)
or
receiver = call.(SummaryCall).getReceiver() and
if receiver.(ParameterNodeImpl).isParameterOf(_, any(ParameterPosition pos | pos.isBlock()))