mirror of
https://github.com/github/codeql.git
synced 2026-04-30 11:15:13 +02:00
Merge pull request #5311 from hvitved/dataflow/lambda
Data flow: Move C# lambda flow logic into shared library
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
/**
|
||||
* DEPRECATED.
|
||||
*
|
||||
* Provides classes for data flow call contexts.
|
||||
*/
|
||||
|
||||
@@ -15,11 +17,13 @@ private newtype TCallContext =
|
||||
TArgFunctionPointerCallContext(FunctionPointerCall fptrc, int i) { exists(fptrc.getArgument(i)) }
|
||||
|
||||
/**
|
||||
* DEPRECATED.
|
||||
*
|
||||
* A call context.
|
||||
*
|
||||
* A call context records the origin of data flow into callables.
|
||||
*/
|
||||
class CallContext extends TCallContext {
|
||||
deprecated class CallContext extends TCallContext {
|
||||
/** Gets a textual representation of this call context. */
|
||||
string toString() { none() }
|
||||
|
||||
@@ -27,18 +31,20 @@ class CallContext extends TCallContext {
|
||||
Location getLocation() { none() }
|
||||
}
|
||||
|
||||
/** An empty call context. */
|
||||
class EmptyCallContext extends CallContext, TEmptyCallContext {
|
||||
/** DEPRECATED. An empty call context. */
|
||||
deprecated class EmptyCallContext extends CallContext, TEmptyCallContext {
|
||||
override string toString() { result = "<empty>" }
|
||||
|
||||
override EmptyLocation getLocation() { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED.
|
||||
*
|
||||
* An argument call context, that is a call argument through which data flows
|
||||
* into a callable.
|
||||
*/
|
||||
abstract class ArgumentCallContext extends CallContext {
|
||||
abstract deprecated class ArgumentCallContext extends CallContext {
|
||||
/**
|
||||
* Holds if this call context represents the argument at position `i` of the
|
||||
* call expression `call`.
|
||||
@@ -46,8 +52,9 @@ abstract class ArgumentCallContext extends CallContext {
|
||||
abstract predicate isArgument(Expr call, int i);
|
||||
}
|
||||
|
||||
/** An argument of a non-delegate call. */
|
||||
class NonDelegateCallArgumentCallContext extends ArgumentCallContext, TArgNonDelegateCallContext {
|
||||
/** DEPRECATED. An argument of a non-delegate call. */
|
||||
deprecated class NonDelegateCallArgumentCallContext extends ArgumentCallContext,
|
||||
TArgNonDelegateCallContext {
|
||||
Expr arg;
|
||||
|
||||
NonDelegateCallArgumentCallContext() { this = TArgNonDelegateCallContext(arg) }
|
||||
@@ -61,8 +68,8 @@ class NonDelegateCallArgumentCallContext extends ArgumentCallContext, TArgNonDel
|
||||
override Location getLocation() { result = arg.getLocation() }
|
||||
}
|
||||
|
||||
/** An argument of a delegate or function pointer call. */
|
||||
class DelegateLikeCallArgumentCallContext extends ArgumentCallContext {
|
||||
/** DEPRECATED. An argument of a delegate or function pointer call. */
|
||||
deprecated class DelegateLikeCallArgumentCallContext extends ArgumentCallContext {
|
||||
DelegateLikeCall dc;
|
||||
int arg;
|
||||
|
||||
@@ -80,10 +87,10 @@ class DelegateLikeCallArgumentCallContext extends ArgumentCallContext {
|
||||
override Location getLocation() { result = dc.getArgument(arg).getLocation() }
|
||||
}
|
||||
|
||||
/** An argument of a delegate call. */
|
||||
class DelegateCallArgumentCallContext extends DelegateLikeCallArgumentCallContext,
|
||||
/** DEPRECATED. An argument of a delegate call. */
|
||||
deprecated class DelegateCallArgumentCallContext extends DelegateLikeCallArgumentCallContext,
|
||||
TArgDelegateCallContext { }
|
||||
|
||||
/** An argument of a function pointer call. */
|
||||
class FunctionPointerCallArgumentCallContext extends DelegateLikeCallArgumentCallContext,
|
||||
/** DEPRECATED. An argument of a function pointer call. */
|
||||
deprecated class FunctionPointerCallArgumentCallContext extends DelegateLikeCallArgumentCallContext,
|
||||
TArgFunctionPointerCallContext { }
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
private import csharp
|
||||
private import cil
|
||||
private import dotnet
|
||||
private import DataFlowPublic
|
||||
private import DataFlowPrivate
|
||||
private import DelegateDataFlow
|
||||
private import FlowSummaryImpl as FlowSummaryImpl
|
||||
private import semmle.code.csharp.dataflow.FlowSummary
|
||||
private import semmle.code.csharp.dispatch.Dispatch
|
||||
@@ -131,45 +131,24 @@ private module Cached {
|
||||
import Cached
|
||||
|
||||
private module DispatchImpl {
|
||||
private import CallContext
|
||||
|
||||
/**
|
||||
* Gets a viable run-time target for the delegate call `call`, requiring
|
||||
* call context `cc`.
|
||||
*/
|
||||
private DataFlowCallable viableDelegateCallable(DataFlowCall call, CallContext cc) {
|
||||
result = call.(DelegateDataFlowCall).getARuntimeTarget(cc)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the set of viable implementations that can be called by `call`
|
||||
* might be improved by knowing the call context. This is the case if the
|
||||
* call is a delegate call, or if the qualifier accesses a parameter of
|
||||
* the enclosing callable `c` (including the implicit `this` parameter).
|
||||
*/
|
||||
predicate mayBenefitFromCallContext(DataFlowCall call, Callable c) {
|
||||
predicate mayBenefitFromCallContext(NonDelegateDataFlowCall call, Callable c) {
|
||||
c = call.getEnclosingCallable() and
|
||||
(
|
||||
exists(CallContext cc | exists(viableDelegateCallable(call, cc)) |
|
||||
not cc instanceof EmptyCallContext
|
||||
)
|
||||
or
|
||||
call.(NonDelegateDataFlowCall).getDispatchCall().mayBenefitFromCallContext()
|
||||
)
|
||||
call.getDispatchCall().mayBenefitFromCallContext()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a viable dispatch target of `call` in the context `ctx`. This is
|
||||
* restricted to those `call`s for which a context might make a difference.
|
||||
*/
|
||||
DataFlowCallable viableImplInCallContext(DataFlowCall call, DataFlowCall ctx) {
|
||||
exists(ArgumentCallContext cc | result = viableDelegateCallable(call, cc) |
|
||||
cc.isArgument(ctx.getExpr(), _)
|
||||
)
|
||||
or
|
||||
DataFlowCallable viableImplInCallContext(NonDelegateDataFlowCall call, DataFlowCall ctx) {
|
||||
result =
|
||||
call.(NonDelegateDataFlowCall)
|
||||
.getDispatchCall()
|
||||
call.getDispatchCall()
|
||||
.getADynamicTargetInCallContext(ctx.(NonDelegateDataFlowCall).getDispatchCall())
|
||||
.getUnboundDeclaration()
|
||||
}
|
||||
@@ -301,12 +280,7 @@ class NonDelegateDataFlowCall extends DataFlowCall, TNonDelegateCall {
|
||||
}
|
||||
|
||||
/** A delegate call relevant for data flow. */
|
||||
abstract class DelegateDataFlowCall extends DataFlowCall {
|
||||
/** Gets a viable run-time target of this call requiring call context `cc`. */
|
||||
abstract DataFlowCallable getARuntimeTarget(CallContext::CallContext cc);
|
||||
|
||||
override DataFlowCallable getARuntimeTarget() { result = this.getARuntimeTarget(_) }
|
||||
}
|
||||
abstract class DelegateDataFlowCall extends DataFlowCall { }
|
||||
|
||||
/** An explicit delegate or function pointer call relevant for data flow. */
|
||||
class ExplicitDelegateLikeDataFlowCall extends DelegateDataFlowCall, TExplicitDelegateLikeCall {
|
||||
@@ -315,8 +289,11 @@ class ExplicitDelegateLikeDataFlowCall extends DelegateDataFlowCall, TExplicitDe
|
||||
|
||||
ExplicitDelegateLikeDataFlowCall() { this = TExplicitDelegateLikeCall(cfn, dc) }
|
||||
|
||||
override DataFlowCallable getARuntimeTarget(CallContext::CallContext cc) {
|
||||
result = getCallableForDataFlow(dc.getARuntimeTarget(cc))
|
||||
/** Gets the underlying call. */
|
||||
DelegateLikeCall getCall() { result = dc }
|
||||
|
||||
override DataFlowCallable getARuntimeTarget() {
|
||||
none() // handled by the shared library
|
||||
}
|
||||
|
||||
override ControlFlow::Nodes::ElementNode getControlFlowNode() { result = cfn }
|
||||
@@ -389,11 +366,11 @@ class SummaryDelegateCall extends DelegateDataFlowCall, TSummaryDelegateCall {
|
||||
|
||||
SummaryDelegateCall() { this = TSummaryDelegateCall(c, pos) }
|
||||
|
||||
override DataFlowCallable getARuntimeTarget(CallContext::CallContext cc) {
|
||||
exists(SummaryDelegateParameterSink p |
|
||||
p.isParameterOf(c, pos) and
|
||||
result = p.getARuntimeTarget(cc)
|
||||
)
|
||||
/** Gets the parameter node that this delegate call targets. */
|
||||
ParameterNode getParameterNode() { result.isParameterOf(c, pos) }
|
||||
|
||||
override DataFlowCallable getARuntimeTarget() {
|
||||
none() // handled by the shared library
|
||||
}
|
||||
|
||||
override ControlFlow::Nodes::ElementNode getControlFlowNode() { none() }
|
||||
|
||||
@@ -26,15 +26,243 @@ predicate accessPathCostLimits(int apLimit, int tupleLimit) {
|
||||
tupleLimit = 1000
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a simple data-flow analysis for resolving lambda calls. The analysis
|
||||
* currently excludes read-steps, store-steps, and flow-through.
|
||||
*
|
||||
* The analysis uses non-linear recursion: When computing a flow path in or out
|
||||
* of a call, we use the results of the analysis recursively to resolve lamba
|
||||
* calls. For this reason, we cannot reuse the code from `DataFlowImpl.qll` directly.
|
||||
*/
|
||||
private module LambdaFlow {
|
||||
private predicate viableParamNonLambda(DataFlowCall call, int i, ParameterNode p) {
|
||||
p.isParameterOf(viableCallable(call), i)
|
||||
}
|
||||
|
||||
private predicate viableParamLambda(DataFlowCall call, int i, ParameterNode p) {
|
||||
p.isParameterOf(viableCallableLambda(call, _), i)
|
||||
}
|
||||
|
||||
private predicate viableParamArgNonLambda(DataFlowCall call, ParameterNode p, ArgumentNode arg) {
|
||||
exists(int i |
|
||||
viableParamNonLambda(call, i, p) and
|
||||
arg.argumentOf(call, i)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate viableParamArgLambda(DataFlowCall call, ParameterNode p, ArgumentNode arg) {
|
||||
exists(int i |
|
||||
viableParamLambda(call, i, p) and
|
||||
arg.argumentOf(call, i)
|
||||
)
|
||||
}
|
||||
|
||||
private newtype TReturnPositionSimple =
|
||||
TReturnPositionSimple0(DataFlowCallable c, ReturnKind kind) {
|
||||
exists(ReturnNode ret |
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
kind = ret.getKind()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private TReturnPositionSimple getReturnPositionSimple(ReturnNode ret, ReturnKind kind) {
|
||||
result = TReturnPositionSimple0(getNodeEnclosingCallable(ret), kind)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private TReturnPositionSimple viableReturnPosNonLambda(DataFlowCall call, ReturnKind kind) {
|
||||
result = TReturnPositionSimple0(viableCallable(call), kind)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private TReturnPositionSimple viableReturnPosLambda(
|
||||
DataFlowCall call, DataFlowCallOption lastCall, ReturnKind kind
|
||||
) {
|
||||
result = TReturnPositionSimple0(viableCallableLambda(call, lastCall), kind)
|
||||
}
|
||||
|
||||
private predicate viableReturnPosOutNonLambda(
|
||||
DataFlowCall call, TReturnPositionSimple pos, OutNode out
|
||||
) {
|
||||
exists(ReturnKind kind |
|
||||
pos = viableReturnPosNonLambda(call, kind) and
|
||||
out = getAnOutNode(call, kind)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate viableReturnPosOutLambda(
|
||||
DataFlowCall call, DataFlowCallOption lastCall, TReturnPositionSimple pos, OutNode out
|
||||
) {
|
||||
exists(ReturnKind kind |
|
||||
pos = viableReturnPosLambda(call, lastCall, kind) and
|
||||
out = getAnOutNode(call, kind)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow (inter-procedurally) from `node` (of type `t`) to
|
||||
* the lambda call `lambdaCall`.
|
||||
*
|
||||
* The parameter `toReturn` indicates whether the path from `node` to
|
||||
* `lambdaCall` goes through a return, and `toJump` whether the path goes
|
||||
* through a jump step.
|
||||
*
|
||||
* The call context `lastCall` records the last call on the path from `node`
|
||||
* to `lambdaCall`, if any. That is, `lastCall` is able to target the enclosing
|
||||
* callable of `lambdaCall`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revLambdaFlow(
|
||||
DataFlowCall lambdaCall, LambdaCallKind kind, Node node, DataFlowType t, boolean toReturn,
|
||||
boolean toJump, DataFlowCallOption lastCall
|
||||
) {
|
||||
revLambdaFlow0(lambdaCall, kind, node, t, toReturn, toJump, lastCall) and
|
||||
if node instanceof CastNode or node instanceof ArgumentNode or node instanceof ReturnNode
|
||||
then compatibleTypes(t, getNodeType(node))
|
||||
else any()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate revLambdaFlow0(
|
||||
DataFlowCall lambdaCall, LambdaCallKind kind, Node node, DataFlowType t, boolean toReturn,
|
||||
boolean toJump, DataFlowCallOption lastCall
|
||||
) {
|
||||
lambdaCall(lambdaCall, kind, node) and
|
||||
t = getNodeType(node) and
|
||||
toReturn = false and
|
||||
toJump = false and
|
||||
lastCall = TDataFlowCallNone()
|
||||
or
|
||||
// local flow
|
||||
exists(Node mid, DataFlowType t0 |
|
||||
revLambdaFlow(lambdaCall, kind, mid, t0, toReturn, toJump, lastCall)
|
||||
|
|
||||
simpleLocalFlowStep(node, mid) and
|
||||
t = t0
|
||||
or
|
||||
exists(boolean preservesValue |
|
||||
additionalLambdaFlowStep(node, mid, preservesValue) and
|
||||
getNodeEnclosingCallable(node) = getNodeEnclosingCallable(mid)
|
||||
|
|
||||
preservesValue = false and
|
||||
t = getNodeType(node)
|
||||
or
|
||||
preservesValue = true and
|
||||
t = t0
|
||||
)
|
||||
)
|
||||
or
|
||||
// jump step
|
||||
exists(Node mid, DataFlowType t0 |
|
||||
revLambdaFlow(lambdaCall, kind, mid, t0, _, _, _) and
|
||||
toReturn = false and
|
||||
toJump = true and
|
||||
lastCall = TDataFlowCallNone()
|
||||
|
|
||||
jumpStep(node, mid) and
|
||||
t = t0
|
||||
or
|
||||
exists(boolean preservesValue |
|
||||
additionalLambdaFlowStep(node, mid, preservesValue) and
|
||||
getNodeEnclosingCallable(node) != getNodeEnclosingCallable(mid)
|
||||
|
|
||||
preservesValue = false and
|
||||
t = getNodeType(node)
|
||||
or
|
||||
preservesValue = true and
|
||||
t = t0
|
||||
)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
exists(ParameterNode p, DataFlowCallOption lastCall0, DataFlowCall call |
|
||||
revLambdaFlowIn(lambdaCall, kind, p, t, toJump, lastCall0) and
|
||||
(
|
||||
if lastCall0 = TDataFlowCallNone() and toJump = false
|
||||
then lastCall = TDataFlowCallSome(call)
|
||||
else lastCall = lastCall0
|
||||
) and
|
||||
toReturn = false
|
||||
|
|
||||
viableParamArgNonLambda(call, p, node)
|
||||
or
|
||||
viableParamArgLambda(call, p, node) // non-linear recursion
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(TReturnPositionSimple pos |
|
||||
revLambdaFlowOut(lambdaCall, kind, pos, t, toJump, lastCall) and
|
||||
getReturnPositionSimple(node, node.(ReturnNode).getKind()) = pos and
|
||||
toReturn = true
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate revLambdaFlowOutLambdaCall(
|
||||
DataFlowCall lambdaCall, LambdaCallKind kind, OutNode out, DataFlowType t, boolean toJump,
|
||||
DataFlowCall call, DataFlowCallOption lastCall
|
||||
) {
|
||||
revLambdaFlow(lambdaCall, kind, out, t, _, toJump, lastCall) and
|
||||
exists(ReturnKindExt rk |
|
||||
out = rk.getAnOutNode(call) and
|
||||
lambdaCall(call, _, _)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate revLambdaFlowOut(
|
||||
DataFlowCall lambdaCall, LambdaCallKind kind, TReturnPositionSimple pos, DataFlowType t,
|
||||
boolean toJump, DataFlowCallOption lastCall
|
||||
) {
|
||||
exists(DataFlowCall call, OutNode out |
|
||||
revLambdaFlow(lambdaCall, kind, out, t, _, toJump, lastCall) and
|
||||
viableReturnPosOutNonLambda(call, pos, out)
|
||||
or
|
||||
// non-linear recursion
|
||||
revLambdaFlowOutLambdaCall(lambdaCall, kind, out, t, toJump, call, lastCall) and
|
||||
viableReturnPosOutLambda(call, _, pos, out)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate revLambdaFlowIn(
|
||||
DataFlowCall lambdaCall, LambdaCallKind kind, ParameterNode p, DataFlowType t, boolean toJump,
|
||||
DataFlowCallOption lastCall
|
||||
) {
|
||||
revLambdaFlow(lambdaCall, kind, p, t, false, toJump, lastCall)
|
||||
}
|
||||
}
|
||||
|
||||
private DataFlowCallable viableCallableExt(DataFlowCall call) {
|
||||
result = viableCallable(call)
|
||||
or
|
||||
result = viableCallableLambda(call, _)
|
||||
}
|
||||
|
||||
cached
|
||||
private module Cached {
|
||||
/**
|
||||
* Gets a viable target for the lambda call `call`.
|
||||
*
|
||||
* `lastCall` records the call required to reach `call` in order for the result
|
||||
* to be a viable target, if any.
|
||||
*/
|
||||
cached
|
||||
DataFlowCallable viableCallableLambda(DataFlowCall call, DataFlowCallOption lastCall) {
|
||||
exists(Node creation, LambdaCallKind kind |
|
||||
LambdaFlow::revLambdaFlow(call, kind, creation, _, _, _, lastCall) and
|
||||
lambdaCreation(creation, kind, result)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `p` is the `i`th parameter of a viable dispatch target of `call`.
|
||||
* The instance parameter is considered to have index `-1`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate viableParam(DataFlowCall call, int i, ParameterNode p) {
|
||||
p.isParameterOf(viableCallable(call), i)
|
||||
p.isParameterOf(viableCallableExt(call), i)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -52,7 +280,7 @@ private module Cached {
|
||||
|
||||
pragma[nomagic]
|
||||
private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) {
|
||||
viableCallable(call) = result.getCallable() and
|
||||
viableCallableExt(call) = result.getCallable() and
|
||||
kind = result.getKind()
|
||||
}
|
||||
|
||||
@@ -317,6 +545,35 @@ private module Cached {
|
||||
|
||||
cached
|
||||
private module DispatchWithCallContext {
|
||||
/**
|
||||
* Holds if the set of viable implementations that can be called by `call`
|
||||
* might be improved by knowing the call context.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate mayBenefitFromCallContextExt(DataFlowCall call, DataFlowCallable callable) {
|
||||
mayBenefitFromCallContext(call, callable)
|
||||
or
|
||||
callable = call.getEnclosingCallable() and
|
||||
exists(viableCallableLambda(call, TDataFlowCallSome(_)))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a viable dispatch target of `call` in the context `ctx`. This is
|
||||
* restricted to those `call`s for which a context might make a difference.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private DataFlowCallable viableImplInCallContextExt(DataFlowCall call, DataFlowCall ctx) {
|
||||
result = viableImplInCallContext(call, ctx)
|
||||
or
|
||||
result = viableCallableLambda(call, TDataFlowCallSome(ctx))
|
||||
or
|
||||
exists(DataFlowCallable enclosing |
|
||||
mayBenefitFromCallContextExt(call, enclosing) and
|
||||
enclosing = viableCallableExt(ctx) and
|
||||
result = viableCallableLambda(call, TDataFlowCallNone())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the call context `ctx` reduces the set of viable run-time
|
||||
* dispatch targets of call `call` in `c`.
|
||||
@@ -324,10 +581,10 @@ private module Cached {
|
||||
cached
|
||||
predicate reducedViableImplInCallContext(DataFlowCall call, DataFlowCallable c, DataFlowCall ctx) {
|
||||
exists(int tgts, int ctxtgts |
|
||||
mayBenefitFromCallContext(call, c) and
|
||||
c = viableCallable(ctx) and
|
||||
ctxtgts = count(viableImplInCallContext(call, ctx)) and
|
||||
tgts = strictcount(viableCallable(call)) and
|
||||
mayBenefitFromCallContextExt(call, c) and
|
||||
c = viableCallableExt(ctx) and
|
||||
ctxtgts = count(viableImplInCallContextExt(call, ctx)) and
|
||||
tgts = strictcount(viableCallableExt(call)) and
|
||||
ctxtgts < tgts
|
||||
)
|
||||
}
|
||||
@@ -339,7 +596,7 @@ private module Cached {
|
||||
*/
|
||||
cached
|
||||
DataFlowCallable prunedViableImplInCallContext(DataFlowCall call, DataFlowCall ctx) {
|
||||
result = viableImplInCallContext(call, ctx) and
|
||||
result = viableImplInCallContextExt(call, ctx) and
|
||||
reducedViableImplInCallContext(call, _, ctx)
|
||||
}
|
||||
|
||||
@@ -351,10 +608,10 @@ private module Cached {
|
||||
cached
|
||||
predicate reducedViableImplInReturn(DataFlowCallable c, DataFlowCall call) {
|
||||
exists(int tgts, int ctxtgts |
|
||||
mayBenefitFromCallContext(call, _) and
|
||||
c = viableCallable(call) and
|
||||
ctxtgts = count(DataFlowCall ctx | c = viableImplInCallContext(call, ctx)) and
|
||||
tgts = strictcount(DataFlowCall ctx | viableCallable(ctx) = call.getEnclosingCallable()) and
|
||||
mayBenefitFromCallContextExt(call, _) and
|
||||
c = viableCallableExt(call) and
|
||||
ctxtgts = count(DataFlowCall ctx | c = viableImplInCallContextExt(call, ctx)) and
|
||||
tgts = strictcount(DataFlowCall ctx | viableCallableExt(ctx) = call.getEnclosingCallable()) and
|
||||
ctxtgts < tgts
|
||||
)
|
||||
}
|
||||
@@ -367,7 +624,7 @@ private module Cached {
|
||||
*/
|
||||
cached
|
||||
DataFlowCallable prunedViableImplInCallContextReverse(DataFlowCall call, DataFlowCall ctx) {
|
||||
result = viableImplInCallContext(call, ctx) and
|
||||
result = viableImplInCallContextExt(call, ctx) and
|
||||
reducedViableImplInReturn(result, call)
|
||||
}
|
||||
}
|
||||
@@ -481,6 +738,11 @@ private module Cached {
|
||||
TBooleanNone() or
|
||||
TBooleanSome(boolean b) { b = true or b = false }
|
||||
|
||||
cached
|
||||
newtype TDataFlowCallOption =
|
||||
TDataFlowCallNone() or
|
||||
TDataFlowCallSome(DataFlowCall call)
|
||||
|
||||
cached
|
||||
newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, _, t) }
|
||||
|
||||
@@ -777,7 +1039,7 @@ ReturnPosition getReturnPosition(ReturnNodeExt ret) {
|
||||
|
||||
bindingset[cc, callable]
|
||||
predicate resolveReturn(CallContext cc, DataFlowCallable callable, DataFlowCall call) {
|
||||
cc instanceof CallContextAny and callable = viableCallable(call)
|
||||
cc instanceof CallContextAny and callable = viableCallableExt(call)
|
||||
or
|
||||
exists(DataFlowCallable c0, DataFlowCall call0 |
|
||||
call0.getEnclosingCallable() = callable and
|
||||
@@ -791,14 +1053,14 @@ DataFlowCallable resolveCall(DataFlowCall call, CallContext cc) {
|
||||
exists(DataFlowCall ctx | cc = TSpecificCall(ctx) |
|
||||
if reducedViableImplInCallContext(call, _, ctx)
|
||||
then result = prunedViableImplInCallContext(call, ctx)
|
||||
else result = viableCallable(call)
|
||||
else result = viableCallableExt(call)
|
||||
)
|
||||
or
|
||||
result = viableCallable(call) and cc instanceof CallContextSomeCall
|
||||
result = viableCallableExt(call) and cc instanceof CallContextSomeCall
|
||||
or
|
||||
result = viableCallable(call) and cc instanceof CallContextAny
|
||||
result = viableCallableExt(call) and cc instanceof CallContextAny
|
||||
or
|
||||
result = viableCallable(call) and cc instanceof CallContextReturn
|
||||
result = viableCallableExt(call) and cc instanceof CallContextReturn
|
||||
}
|
||||
|
||||
predicate read = readStep/3;
|
||||
@@ -812,6 +1074,19 @@ class BooleanOption extends TBooleanOption {
|
||||
}
|
||||
}
|
||||
|
||||
/** An optional `DataFlowCall`. */
|
||||
class DataFlowCallOption extends TDataFlowCallOption {
|
||||
string toString() {
|
||||
this = TDataFlowCallNone() and
|
||||
result = "(none)"
|
||||
or
|
||||
exists(DataFlowCall call |
|
||||
this = TDataFlowCallSome(call) and
|
||||
result = call.toString()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** Content tagged with the type of a containing object. */
|
||||
class TypedContent extends MkTypedContent {
|
||||
private Content c;
|
||||
|
||||
@@ -5,7 +5,6 @@ private import DataFlowPublic
|
||||
private import DataFlowDispatch
|
||||
private import DataFlowImplCommon
|
||||
private import ControlFlowReachability
|
||||
private import DelegateDataFlow
|
||||
private import FlowSummaryImpl as FlowSummaryImpl
|
||||
private import semmle.code.csharp.dataflow.FlowSummary
|
||||
private import semmle.code.csharp.Caching
|
||||
@@ -292,8 +291,8 @@ module LocalFlow {
|
||||
*/
|
||||
private predicate localFlowSsaInput(Node nodeFrom, Ssa::Definition def, Ssa::Definition next) {
|
||||
exists(ControlFlow::BasicBlock bb, int i | SsaImpl::lastRefBeforeRedef(def, bb, i, next) |
|
||||
def = nodeFrom.(SsaDefinitionNode).getDefinition() and
|
||||
def.definesAt(_, bb, i)
|
||||
def.definesAt(_, bb, i) and
|
||||
def = getSsaDefinition(nodeFrom)
|
||||
or
|
||||
nodeFrom.asExprAtNode(bb.getNode(i)) instanceof AssignableRead
|
||||
)
|
||||
@@ -433,7 +432,7 @@ private class Argument extends Expr {
|
||||
this = dc.getQualifier() and arg = -1 and not dc.getAStaticTarget().(Modifiable).isStatic()
|
||||
).getCall()
|
||||
or
|
||||
this = call.(DelegateCall).getArgument(arg)
|
||||
this = call.(DelegateLikeCall).getArgument(arg)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2022,3 +2021,69 @@ class Unit extends TUnit {
|
||||
* This predicate is only used for consistency checks.
|
||||
*/
|
||||
predicate isImmutableOrUnobservable(Node n) { none() }
|
||||
|
||||
class LambdaCallKind = Unit;
|
||||
|
||||
/** Holds if `creation` is an expression that creates a delegate for `c`. */
|
||||
predicate lambdaCreation(ExprNode creation, LambdaCallKind kind, DataFlowCallable c) {
|
||||
exists(Expr e | e = creation.getExpr() |
|
||||
c = e.(AnonymousFunctionExpr)
|
||||
or
|
||||
c = e.(CallableAccess).getTarget().getUnboundDeclaration()
|
||||
or
|
||||
c = e.(AddressOfExpr).getOperand().(CallableAccess).getTarget().getUnboundDeclaration()
|
||||
) and
|
||||
kind = TMkUnit()
|
||||
}
|
||||
|
||||
private class LambdaConfiguration extends ControlFlowReachabilityConfiguration {
|
||||
LambdaConfiguration() { this = "LambdaConfiguration" }
|
||||
|
||||
override predicate candidate(
|
||||
Expr e1, Expr e2, ControlFlowElement scope, boolean exactScope, boolean isSuccessor
|
||||
) {
|
||||
e1 = e2.(DelegateLikeCall).getExpr() and
|
||||
exactScope = false and
|
||||
scope = e2 and
|
||||
isSuccessor = true
|
||||
or
|
||||
e1 = e2.(DelegateCreation).getArgument() and
|
||||
exactScope = false and
|
||||
scope = e2 and
|
||||
isSuccessor = true
|
||||
}
|
||||
}
|
||||
|
||||
/** Holds if `call` is a lambda call where `receiver` is the lambda expression. */
|
||||
predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) {
|
||||
(
|
||||
exists(LambdaConfiguration x, DelegateLikeCall dc |
|
||||
x.hasExprPath(dc.getExpr(), receiver.(ExprNode).getControlFlowNode(), dc,
|
||||
call.getControlFlowNode())
|
||||
)
|
||||
or
|
||||
receiver = call.(SummaryDelegateCall).getParameterNode()
|
||||
) and
|
||||
kind = TMkUnit()
|
||||
}
|
||||
|
||||
/** Extra data-flow steps needed for lamba flow analysis. */
|
||||
predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preservesValue) {
|
||||
exists(Ssa::Definition def |
|
||||
LocalFlow::localSsaFlowStep(def, nodeFrom, nodeTo) and
|
||||
LocalFlow::usesInstanceField(def) and
|
||||
preservesValue = true
|
||||
)
|
||||
or
|
||||
exists(LambdaConfiguration x, DelegateCreation dc |
|
||||
x.hasExprPath(dc.getArgument(), nodeFrom.(ExprNode).getControlFlowNode(), dc,
|
||||
nodeTo.(ExprNode).getControlFlowNode()) and
|
||||
preservesValue = false
|
||||
)
|
||||
or
|
||||
exists(AddEventExpr aee |
|
||||
nodeFrom.asExpr() = aee.getRValue() and
|
||||
nodeTo.asExpr().(EventRead).getTarget() = aee.getTarget() and
|
||||
preservesValue = false
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
/**
|
||||
* DEPRECATED.
|
||||
*
|
||||
* INTERNAL: Do not use.
|
||||
*
|
||||
* Provides classes for resolving delegate calls.
|
||||
@@ -108,7 +110,7 @@ abstract private class DelegateLikeFlowSink extends DataFlow::Node {
|
||||
* possible delegates resolved on line 6.
|
||||
*/
|
||||
cached
|
||||
Callable getARuntimeTarget(CallContext context) {
|
||||
deprecated Callable getARuntimeTarget(CallContext context) {
|
||||
exists(DelegateLikeFlowSource dfs |
|
||||
flowsFrom(this, dfs, _, context) and
|
||||
result = dfs.getCallable()
|
||||
@@ -117,7 +119,7 @@ abstract private class DelegateLikeFlowSink extends DataFlow::Node {
|
||||
}
|
||||
|
||||
/** A delegate or function pointer call expression. */
|
||||
class DelegateLikeCallExpr extends DelegateLikeFlowSink, DataFlow::ExprNode {
|
||||
deprecated class DelegateLikeCallExpr extends DelegateLikeFlowSink, DataFlow::ExprNode {
|
||||
DelegateLikeCall dc;
|
||||
|
||||
DelegateLikeCallExpr() { this.getExpr() = dc.getExpr() }
|
||||
@@ -126,16 +128,8 @@ class DelegateLikeCallExpr extends DelegateLikeFlowSink, DataFlow::ExprNode {
|
||||
DelegateLikeCall getCall() { result = dc }
|
||||
}
|
||||
|
||||
/** A parameter of delegate type belonging to a callable with a flow summary. */
|
||||
class SummaryDelegateParameterSink extends DelegateLikeFlowSink, ParameterNode {
|
||||
SummaryDelegateParameterSink() {
|
||||
this.getType() instanceof SystemLinqExpressions::DelegateExtType and
|
||||
this.isParameterOf(any(SummarizedCallable c), _)
|
||||
}
|
||||
}
|
||||
|
||||
/** A delegate expression that is added to an event. */
|
||||
class AddEventSource extends DelegateLikeFlowSink, DataFlow::ExprNode {
|
||||
deprecated class AddEventSource extends DelegateLikeFlowSink, DataFlow::ExprNode {
|
||||
AddEventExpr ae;
|
||||
|
||||
AddEventSource() { this.getExpr() = ae.getRValue() }
|
||||
@@ -173,7 +167,7 @@ private class NormalReturnNode extends Node {
|
||||
* `node` goes through a returned expression. The call context `lastCall`
|
||||
* records the last call on the path from `node` to `sink`, if any.
|
||||
*/
|
||||
private predicate flowsFrom(
|
||||
deprecated private predicate flowsFrom(
|
||||
DelegateLikeFlowSink sink, DataFlow::Node node, boolean isReturned, CallContext lastCall
|
||||
) {
|
||||
// Base case
|
||||
@@ -244,7 +238,7 @@ private predicate flowsFrom(
|
||||
* previous call if it exists, otherwise `call` is the last call.
|
||||
*/
|
||||
bindingset[call, i]
|
||||
private CallContext getLastCall(CallContext prevLastCall, Expr call, int i) {
|
||||
deprecated private CallContext getLastCall(CallContext prevLastCall, Expr call, int i) {
|
||||
prevLastCall instanceof EmptyCallContext and
|
||||
result.(ArgumentCallContext).isArgument(call, i)
|
||||
or
|
||||
@@ -263,7 +257,7 @@ private predicate flowIntoNonDelegateCall(NonDelegateCall call, Expr arg, DotNet
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate flowIntoDelegateCall(DelegateLikeCall call, Callable c, Expr arg, int i) {
|
||||
deprecated private predicate flowIntoDelegateCall(DelegateLikeCall call, Callable c, Expr arg, int i) {
|
||||
exists(DelegateLikeFlowSource dfs, DelegateLikeCallExpr dce |
|
||||
// the call context is irrelevant because the delegate call
|
||||
// itself will be the context
|
||||
@@ -280,7 +274,7 @@ private predicate flowOutOfNonDelegateCall(NonDelegateCall call, NormalReturnNod
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate flowOutOfDelegateCall(
|
||||
deprecated private predicate flowOutOfDelegateCall(
|
||||
DelegateLikeCall dc, NormalReturnNode ret, CallContext lastCall
|
||||
) {
|
||||
exists(DelegateLikeFlowSource dfs, DelegateLikeCallExpr dce, Callable c |
|
||||
|
||||
@@ -235,7 +235,6 @@ private module CallGraph {
|
||||
}
|
||||
|
||||
private module SimpleDelegateAnalysis {
|
||||
private import semmle.code.csharp.dataflow.internal.DelegateDataFlow
|
||||
private import semmle.code.csharp.dataflow.internal.Steps
|
||||
private import semmle.code.csharp.frameworks.system.linq.Expressions
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@ import Expr
|
||||
import semmle.code.csharp.Callable
|
||||
import semmle.code.csharp.dataflow.CallContext as CallContext
|
||||
private import semmle.code.csharp.dataflow.internal.DelegateDataFlow
|
||||
private import semmle.code.csharp.dataflow.internal.DataFlowDispatch
|
||||
private import semmle.code.csharp.dataflow.internal.DataFlowImplCommon
|
||||
private import semmle.code.csharp.dispatch.Dispatch
|
||||
private import dotnet
|
||||
|
||||
@@ -536,10 +538,12 @@ class DelegateLikeCall extends Call, DelegateLikeCall_ {
|
||||
override Callable getTarget() { none() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `getARuntimeTarget/0` instead.
|
||||
*
|
||||
* Gets a potential run-time target of this delegate or function pointer call in the given
|
||||
* call context `cc`.
|
||||
*/
|
||||
Callable getARuntimeTarget(CallContext::CallContext cc) {
|
||||
deprecated Callable getARuntimeTarget(CallContext::CallContext cc) {
|
||||
exists(DelegateLikeCallExpr call |
|
||||
this = call.getCall() and
|
||||
result = call.getARuntimeTarget(cc)
|
||||
@@ -562,7 +566,12 @@ class DelegateLikeCall extends Call, DelegateLikeCall_ {
|
||||
*/
|
||||
Expr getExpr() { result = this.getChild(-1) }
|
||||
|
||||
override Callable getARuntimeTarget() { result = getARuntimeTarget(_) }
|
||||
final override Callable getARuntimeTarget() {
|
||||
exists(ExplicitDelegateLikeDataFlowCall call |
|
||||
this = call.getCall() and
|
||||
result = viableCallableLambda(call, _)
|
||||
)
|
||||
}
|
||||
|
||||
override Expr getRuntimeArgument(int i) { result = getArgument(i) }
|
||||
}
|
||||
@@ -582,10 +591,12 @@ class DelegateLikeCall extends Call, DelegateLikeCall_ {
|
||||
*/
|
||||
class DelegateCall extends DelegateLikeCall, @delegate_invocation_expr {
|
||||
/**
|
||||
* DEPRECATED: Use `getARuntimeTarget/0` instead.
|
||||
*
|
||||
* Gets a potential run-time target of this delegate call in the given
|
||||
* call context `cc`.
|
||||
*/
|
||||
override Callable getARuntimeTarget(CallContext::CallContext cc) {
|
||||
deprecated override Callable getARuntimeTarget(CallContext::CallContext cc) {
|
||||
result = DelegateLikeCall.super.getARuntimeTarget(cc)
|
||||
or
|
||||
exists(AddEventSource aes, CallContext::CallContext cc2 |
|
||||
@@ -601,16 +612,16 @@ class DelegateCall extends DelegateLikeCall, @delegate_invocation_expr {
|
||||
)
|
||||
}
|
||||
|
||||
private AddEventSource getAnAddEventSource(Callable enclosingCallable) {
|
||||
deprecated private AddEventSource getAnAddEventSource(Callable enclosingCallable) {
|
||||
this.getExpr().(EventAccess).getTarget() = result.getEvent() and
|
||||
enclosingCallable = result.getExpr().getEnclosingCallable()
|
||||
}
|
||||
|
||||
private AddEventSource getAnAddEventSourceSameEnclosingCallable() {
|
||||
deprecated private AddEventSource getAnAddEventSourceSameEnclosingCallable() {
|
||||
result = getAnAddEventSource(this.getEnclosingCallable())
|
||||
}
|
||||
|
||||
private AddEventSource getAnAddEventSourceDifferentEnclosingCallable() {
|
||||
deprecated private AddEventSource getAnAddEventSourceDifferentEnclosingCallable() {
|
||||
exists(Callable c | result = getAnAddEventSource(c) | c != this.getEnclosingCallable())
|
||||
}
|
||||
|
||||
|
||||
@@ -124,4 +124,13 @@ class DelegateFlow
|
||||
delegate*<Action<int>, void> fnptr = &M2;
|
||||
fnptr((i) => { });
|
||||
}
|
||||
|
||||
void M19(Action a, bool b)
|
||||
{
|
||||
if (b)
|
||||
a = () => {};
|
||||
a();
|
||||
}
|
||||
|
||||
void M20(bool b) => M19(() => {}, b);
|
||||
}
|
||||
|
||||
@@ -1,26 +1,55 @@
|
||||
summaryDelegateCall
|
||||
| file://:0:0:0:0 | valueFactory | DelegateFlow.cs:104:23:104:30 | (...) => ... | DelegateFlow.cs:105:23:105:23 | access to local variable f |
|
||||
| file://:0:0:0:0 | valueFactory | DelegateFlow.cs:106:13:106:20 | (...) => ... | DelegateFlow.cs:107:23:107:23 | access to local variable f |
|
||||
delegateCall
|
||||
| DelegateFlow.cs:9:9:9:12 | delegate call | DelegateFlow.cs:5:10:5:11 | M1 | DelegateFlow.cs:17:12:17:13 | delegate creation of type Action<Int32> |
|
||||
| DelegateFlow.cs:9:9:9:12 | delegate call | DelegateFlow.cs:5:10:5:11 | M1 | DelegateFlow.cs:22:12:22:12 | access to parameter a |
|
||||
| DelegateFlow.cs:9:9:9:12 | delegate call | DelegateFlow.cs:16:12:16:19 | (...) => ... | DelegateFlow.cs:16:12:16:19 | (...) => ... |
|
||||
| DelegateFlow.cs:9:9:9:12 | delegate call | DelegateFlow.cs:27:12:27:19 | (...) => ... | DelegateFlow.cs:22:12:22:12 | access to parameter a |
|
||||
| DelegateFlow.cs:9:9:9:12 | delegate call | DelegateFlow.cs:98:9:98:37 | LocalFunction | DelegateFlow.cs:99:12:99:24 | delegate creation of type Action<Int32> |
|
||||
| DelegateFlow.cs:9:9:9:12 | delegate call | DelegateFlow.cs:119:18:119:27 | (...) => ... | DelegateFlow.cs:114:15:114:15 | access to parameter a |
|
||||
| DelegateFlow.cs:9:9:9:12 | delegate call | DelegateFlow.cs:125:15:125:24 | (...) => ... | DelegateFlow.cs:125:15:125:24 | (...) => ... |
|
||||
| DelegateFlow.cs:11:9:11:12 | delegate call | DelegateFlow.cs:10:13:10:20 | (...) => ... | file://:0:0:0:0 | <empty> |
|
||||
| DelegateFlow.cs:33:9:33:13 | delegate call | DelegateFlow.cs:38:12:38:25 | (...) => ... | DelegateFlow.cs:38:12:38:25 | (...) => ... |
|
||||
| DelegateFlow.cs:38:19:38:22 | delegate call | DelegateFlow.cs:5:10:5:11 | M1 | DelegateFlow.cs:33:12:33:12 | access to parameter a |
|
||||
| DelegateFlow.cs:44:15:44:22 | delegate call | DelegateFlow.cs:43:22:43:29 | (...) => ... | DelegateFlow.cs:50:18:50:23 | dynamic access to member Prop |
|
||||
| DelegateFlow.cs:57:9:57:11 | delegate call | DelegateFlow.cs:53:34:53:47 | (...) => ... | file://:0:0:0:0 | <empty> |
|
||||
| DelegateFlow.cs:57:9:57:14 | delegate call | DelegateFlow.cs:53:40:53:47 | (...) => ... | file://:0:0:0:0 | <empty> |
|
||||
| DelegateFlow.cs:67:9:67:16 | delegate call | DelegateFlow.cs:62:16:62:23 | (...) => ... | file://:0:0:0:0 | <empty> |
|
||||
| DelegateFlow.cs:77:9:77:15 | delegate call | DelegateFlow.cs:55:10:55:11 | M9 | file://:0:0:0:0 | <empty> |
|
||||
| DelegateFlow.cs:77:9:77:15 | delegate call | DelegateFlow.cs:65:10:65:12 | M11 | file://:0:0:0:0 | <empty> |
|
||||
| DelegateFlow.cs:84:9:84:15 | delegate call | DelegateFlow.cs:55:10:55:11 | M9 | DelegateFlow.cs:78:13:78:14 | delegate creation of type EventHandler |
|
||||
| DelegateFlow.cs:84:9:84:15 | delegate call | DelegateFlow.cs:65:10:65:12 | M11 | file://:0:0:0:0 | <empty> |
|
||||
| DelegateFlow.cs:89:35:89:37 | delegate call | DelegateFlow.cs:55:10:55:11 | M9 | DelegateFlow.cs:90:13:90:30 | delegate creation of type MyDelegate |
|
||||
| DelegateFlow.cs:89:35:89:37 | delegate call | DelegateFlow.cs:65:10:65:12 | M11 | DelegateFlow.cs:91:13:91:47 | delegate creation of type MyDelegate |
|
||||
| DelegateFlow.cs:89:35:89:37 | delegate call | DelegateFlow.cs:74:17:74:19 | M12 | DelegateFlow.cs:92:13:92:15 | delegate creation of type MyDelegate |
|
||||
| DelegateFlow.cs:89:35:89:37 | delegate call | DelegateFlow.cs:93:13:93:21 | (...) => ... | DelegateFlow.cs:93:13:93:21 | (...) => ... |
|
||||
| DelegateFlow.cs:9:9:9:12 | delegate call | DelegateFlow.cs:5:10:5:11 | M1 |
|
||||
| DelegateFlow.cs:9:9:9:12 | delegate call | DelegateFlow.cs:16:12:16:19 | (...) => ... |
|
||||
| DelegateFlow.cs:9:9:9:12 | delegate call | DelegateFlow.cs:27:12:27:19 | (...) => ... |
|
||||
| DelegateFlow.cs:9:9:9:12 | delegate call | DelegateFlow.cs:98:9:98:37 | LocalFunction |
|
||||
| DelegateFlow.cs:9:9:9:12 | delegate call | DelegateFlow.cs:119:18:119:27 | (...) => ... |
|
||||
| DelegateFlow.cs:9:9:9:12 | delegate call | DelegateFlow.cs:125:15:125:24 | (...) => ... |
|
||||
| DelegateFlow.cs:11:9:11:12 | delegate call | DelegateFlow.cs:10:13:10:20 | (...) => ... |
|
||||
| DelegateFlow.cs:33:9:33:13 | delegate call | DelegateFlow.cs:38:12:38:25 | (...) => ... |
|
||||
| DelegateFlow.cs:38:19:38:22 | delegate call | DelegateFlow.cs:5:10:5:11 | M1 |
|
||||
| DelegateFlow.cs:44:15:44:22 | delegate call | DelegateFlow.cs:43:22:43:29 | (...) => ... |
|
||||
| DelegateFlow.cs:57:9:57:11 | delegate call | DelegateFlow.cs:53:34:53:47 | (...) => ... |
|
||||
| DelegateFlow.cs:57:9:57:14 | delegate call | DelegateFlow.cs:53:40:53:47 | (...) => ... |
|
||||
| DelegateFlow.cs:67:9:67:16 | delegate call | DelegateFlow.cs:62:16:62:23 | (...) => ... |
|
||||
| DelegateFlow.cs:77:9:77:15 | delegate call | DelegateFlow.cs:55:10:55:11 | M9 |
|
||||
| DelegateFlow.cs:77:9:77:15 | delegate call | DelegateFlow.cs:65:10:65:12 | M11 |
|
||||
| DelegateFlow.cs:84:9:84:15 | delegate call | DelegateFlow.cs:55:10:55:11 | M9 |
|
||||
| DelegateFlow.cs:84:9:84:15 | delegate call | DelegateFlow.cs:65:10:65:12 | M11 |
|
||||
| DelegateFlow.cs:89:35:89:37 | delegate call | DelegateFlow.cs:55:10:55:11 | M9 |
|
||||
| DelegateFlow.cs:89:35:89:37 | delegate call | DelegateFlow.cs:65:10:65:12 | M11 |
|
||||
| DelegateFlow.cs:89:35:89:37 | delegate call | DelegateFlow.cs:74:17:74:19 | M12 |
|
||||
| DelegateFlow.cs:89:35:89:37 | delegate call | DelegateFlow.cs:93:13:93:21 | (...) => ... |
|
||||
| DelegateFlow.cs:114:9:114:16 | function pointer call | DelegateFlow.cs:7:17:7:18 | M2 |
|
||||
| DelegateFlow.cs:125:9:125:25 | function pointer call | DelegateFlow.cs:7:17:7:18 | M2 |
|
||||
| DelegateFlow.cs:132:9:132:11 | delegate call | DelegateFlow.cs:131:17:131:24 | (...) => ... |
|
||||
| DelegateFlow.cs:132:9:132:11 | delegate call | DelegateFlow.cs:135:29:135:36 | (...) => ... |
|
||||
viableLambda
|
||||
| DelegateFlow.cs:9:9:9:12 | delegate call | DelegateFlow.cs:16:9:16:20 | call to method M2 | DelegateFlow.cs:16:12:16:19 | (...) => ... |
|
||||
| DelegateFlow.cs:9:9:9:12 | delegate call | DelegateFlow.cs:17:9:17:14 | call to method M2 | DelegateFlow.cs:5:10:5:11 | M1 |
|
||||
| DelegateFlow.cs:9:9:9:12 | delegate call | DelegateFlow.cs:22:9:22:13 | call to method M2 | DelegateFlow.cs:5:10:5:11 | M1 |
|
||||
| DelegateFlow.cs:9:9:9:12 | delegate call | DelegateFlow.cs:22:9:22:13 | call to method M2 | DelegateFlow.cs:27:12:27:19 | (...) => ... |
|
||||
| DelegateFlow.cs:9:9:9:12 | delegate call | DelegateFlow.cs:99:9:99:25 | call to method M2 | DelegateFlow.cs:98:9:98:37 | LocalFunction |
|
||||
| DelegateFlow.cs:9:9:9:12 | delegate call | DelegateFlow.cs:114:9:114:16 | function pointer call | DelegateFlow.cs:119:18:119:27 | (...) => ... |
|
||||
| DelegateFlow.cs:9:9:9:12 | delegate call | DelegateFlow.cs:125:9:125:25 | function pointer call | DelegateFlow.cs:125:15:125:24 | (...) => ... |
|
||||
| DelegateFlow.cs:11:9:11:12 | delegate call | file://:0:0:0:0 | (none) | DelegateFlow.cs:10:13:10:20 | (...) => ... |
|
||||
| DelegateFlow.cs:33:9:33:13 | delegate call | DelegateFlow.cs:38:9:38:30 | call to method M6 | DelegateFlow.cs:38:12:38:25 | (...) => ... |
|
||||
| DelegateFlow.cs:38:19:38:22 | delegate call | DelegateFlow.cs:33:9:33:13 | delegate call | DelegateFlow.cs:5:10:5:11 | M1 |
|
||||
| DelegateFlow.cs:44:15:44:22 | delegate call | DelegateFlow.cs:50:9:50:14 | dynamic access to member Prop | DelegateFlow.cs:43:22:43:29 | (...) => ... |
|
||||
| DelegateFlow.cs:57:9:57:11 | delegate call | file://:0:0:0:0 | (none) | DelegateFlow.cs:53:34:53:47 | (...) => ... |
|
||||
| DelegateFlow.cs:57:9:57:14 | delegate call | file://:0:0:0:0 | (none) | DelegateFlow.cs:53:40:53:47 | (...) => ... |
|
||||
| DelegateFlow.cs:67:9:67:16 | delegate call | file://:0:0:0:0 | (none) | DelegateFlow.cs:62:16:62:23 | (...) => ... |
|
||||
| DelegateFlow.cs:77:9:77:15 | delegate call | file://:0:0:0:0 | (none) | DelegateFlow.cs:55:10:55:11 | M9 |
|
||||
| DelegateFlow.cs:77:9:77:15 | delegate call | file://:0:0:0:0 | (none) | DelegateFlow.cs:65:10:65:12 | M11 |
|
||||
| DelegateFlow.cs:84:9:84:15 | delegate call | DelegateFlow.cs:78:9:78:15 | call to method M13 | DelegateFlow.cs:55:10:55:11 | M9 |
|
||||
| DelegateFlow.cs:84:9:84:15 | delegate call | file://:0:0:0:0 | (none) | DelegateFlow.cs:65:10:65:12 | M11 |
|
||||
| DelegateFlow.cs:89:35:89:37 | delegate call | DelegateFlow.cs:90:9:90:31 | call to local function M14 | DelegateFlow.cs:55:10:55:11 | M9 |
|
||||
| DelegateFlow.cs:89:35:89:37 | delegate call | DelegateFlow.cs:91:9:91:48 | call to local function M14 | DelegateFlow.cs:65:10:65:12 | M11 |
|
||||
| DelegateFlow.cs:89:35:89:37 | delegate call | DelegateFlow.cs:92:9:92:16 | call to local function M14 | DelegateFlow.cs:74:17:74:19 | M12 |
|
||||
| DelegateFlow.cs:89:35:89:37 | delegate call | DelegateFlow.cs:93:9:93:22 | call to local function M14 | DelegateFlow.cs:93:13:93:21 | (...) => ... |
|
||||
| DelegateFlow.cs:114:9:114:16 | function pointer call | DelegateFlow.cs:119:9:119:28 | call to method M16 | DelegateFlow.cs:7:17:7:18 | M2 |
|
||||
| DelegateFlow.cs:125:9:125:25 | function pointer call | file://:0:0:0:0 | (none) | DelegateFlow.cs:7:17:7:18 | M2 |
|
||||
| DelegateFlow.cs:132:9:132:11 | delegate call | DelegateFlow.cs:135:25:135:40 | call to method M19 | DelegateFlow.cs:135:29:135:36 | (...) => ... |
|
||||
| DelegateFlow.cs:132:9:132:11 | delegate call | file://:0:0:0:0 | (none) | DelegateFlow.cs:131:17:131:24 | (...) => ... |
|
||||
| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Lazy | DelegateFlow.cs:105:9:105:24 | object creation of type Lazy<Int32> | DelegateFlow.cs:104:23:104:30 | (...) => ... |
|
||||
| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Lazy | DelegateFlow.cs:107:9:107:24 | object creation of type Lazy<Int32> | DelegateFlow.cs:106:13:106:20 | (...) => ... |
|
||||
|
||||
@@ -1,22 +1,34 @@
|
||||
import csharp
|
||||
import semmle.code.csharp.dataflow.internal.DataFlowPrivate
|
||||
import semmle.code.csharp.dataflow.internal.DelegateDataFlow
|
||||
import semmle.code.csharp.dataflow.internal.DataFlowImplCommon
|
||||
import semmle.code.csharp.dataflow.internal.DataFlowDispatch
|
||||
|
||||
private class NodeAdjusted extends TNode {
|
||||
string toString() { result = this.(DataFlow::Node).toString() }
|
||||
query predicate delegateCall(DelegateLikeCall dc, Callable c) { c = dc.getARuntimeTarget() }
|
||||
|
||||
private class LocatableDataFlowCallOption extends DataFlowCallOption {
|
||||
Location getLocation() {
|
||||
this = TDataFlowCallNone() and
|
||||
result instanceof EmptyLocation
|
||||
or
|
||||
exists(DataFlowCall call |
|
||||
this = TDataFlowCallSome(call) and
|
||||
result = call.getLocation()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class LocatableDataFlowCall extends TDataFlowCall {
|
||||
string toString() { result = this.(DataFlowCall).toString() }
|
||||
|
||||
Location getLocation() {
|
||||
exists(Location l |
|
||||
l = this.(DataFlow::Node).getLocation() and
|
||||
l = this.(DataFlowCall).getLocation() and
|
||||
if l instanceof SourceLocation then result = l else result instanceof EmptyLocation
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
query predicate summaryDelegateCall(NodeAdjusted sink, Callable c, CallContext::CallContext cc) {
|
||||
c = sink.(SummaryDelegateParameterSink).getARuntimeTarget(cc)
|
||||
}
|
||||
|
||||
query predicate delegateCall(DelegateCall dc, Callable c, CallContext::CallContext cc) {
|
||||
c = dc.getARuntimeTarget(cc)
|
||||
query predicate viableLambda(
|
||||
LocatableDataFlowCall call, LocatableDataFlowCallOption lastCall, DataFlowCallable target
|
||||
) {
|
||||
target = viableCallableLambda(call, lastCall)
|
||||
}
|
||||
|
||||
@@ -1,9 +1,20 @@
|
||||
| FunctionPointerFlow.cs:14:9:14:12 | function pointer call | FunctionPointerFlow.cs:5:24:5:27 | Log1 | FunctionPointerFlow.cs:21:12:21:16 | &... |
|
||||
| FunctionPointerFlow.cs:14:9:14:12 | function pointer call | FunctionPointerFlow.cs:6:24:6:27 | Log2 | FunctionPointerFlow.cs:26:12:26:12 | access to parameter a |
|
||||
| FunctionPointerFlow.cs:14:9:14:12 | function pointer call | FunctionPointerFlow.cs:10:24:10:27 | Log6 | FunctionPointerFlow.cs:26:12:26:12 | access to parameter a |
|
||||
| FunctionPointerFlow.cs:14:9:14:12 | function pointer call | FunctionPointerFlow.cs:46:9:46:44 | LocalFunction | FunctionPointerFlow.cs:47:12:47:25 | &... |
|
||||
| FunctionPointerFlow.cs:16:9:16:12 | function pointer call | FunctionPointerFlow.cs:7:24:7:27 | Log3 | file://:0:0:0:0 | <empty> |
|
||||
| FunctionPointerFlow.cs:41:9:41:15 | function pointer call | FunctionPointerFlow.cs:8:24:8:27 | Log4 | file://:0:0:0:0 | <empty> |
|
||||
| FunctionPointerFlow.cs:54:9:54:16 | function pointer call | FunctionPointerFlow.cs:9:24:9:27 | Log5 | file://:0:0:0:0 | <empty> |
|
||||
| FunctionPointerFlow.cs:59:9:59:13 | function pointer call | FunctionPointerFlow.cs:24:24:24:25 | M4 | FunctionPointerFlow.cs:64:13:64:15 | &... |
|
||||
| FunctionPointerFlow.cs:69:9:69:13 | function pointer call | FunctionPointerFlow.cs:72:24:72:26 | M17 | FunctionPointerFlow.cs:81:13:81:16 | &... |
|
||||
fptrCall
|
||||
| FunctionPointerFlow.cs:14:9:14:12 | function pointer call | FunctionPointerFlow.cs:5:24:5:27 | Log1 |
|
||||
| FunctionPointerFlow.cs:14:9:14:12 | function pointer call | FunctionPointerFlow.cs:6:24:6:27 | Log2 |
|
||||
| FunctionPointerFlow.cs:14:9:14:12 | function pointer call | FunctionPointerFlow.cs:10:24:10:27 | Log6 |
|
||||
| FunctionPointerFlow.cs:14:9:14:12 | function pointer call | FunctionPointerFlow.cs:46:9:46:44 | LocalFunction |
|
||||
| FunctionPointerFlow.cs:16:9:16:12 | function pointer call | FunctionPointerFlow.cs:7:24:7:27 | Log3 |
|
||||
| FunctionPointerFlow.cs:41:9:41:15 | function pointer call | FunctionPointerFlow.cs:8:24:8:27 | Log4 |
|
||||
| FunctionPointerFlow.cs:54:9:54:16 | function pointer call | FunctionPointerFlow.cs:9:24:9:27 | Log5 |
|
||||
| FunctionPointerFlow.cs:59:9:59:13 | function pointer call | FunctionPointerFlow.cs:24:24:24:25 | M4 |
|
||||
| FunctionPointerFlow.cs:69:9:69:13 | function pointer call | FunctionPointerFlow.cs:72:24:72:26 | M17 |
|
||||
fptrCallContext
|
||||
| FunctionPointerFlow.cs:14:9:14:12 | function pointer call | FunctionPointerFlow.cs:21:9:21:17 | call to method M2 | FunctionPointerFlow.cs:5:24:5:27 | Log1 |
|
||||
| FunctionPointerFlow.cs:14:9:14:12 | function pointer call | FunctionPointerFlow.cs:26:9:26:13 | call to method M2 | FunctionPointerFlow.cs:6:24:6:27 | Log2 |
|
||||
| FunctionPointerFlow.cs:14:9:14:12 | function pointer call | FunctionPointerFlow.cs:26:9:26:13 | call to method M2 | FunctionPointerFlow.cs:10:24:10:27 | Log6 |
|
||||
| FunctionPointerFlow.cs:14:9:14:12 | function pointer call | FunctionPointerFlow.cs:47:9:47:26 | call to method M2 | FunctionPointerFlow.cs:46:9:46:44 | LocalFunction |
|
||||
| FunctionPointerFlow.cs:16:9:16:12 | function pointer call | file://:0:0:0:0 | (none) | FunctionPointerFlow.cs:7:24:7:27 | Log3 |
|
||||
| FunctionPointerFlow.cs:41:9:41:15 | function pointer call | file://:0:0:0:0 | (none) | FunctionPointerFlow.cs:8:24:8:27 | Log4 |
|
||||
| FunctionPointerFlow.cs:54:9:54:16 | function pointer call | file://:0:0:0:0 | (none) | FunctionPointerFlow.cs:9:24:9:27 | Log5 |
|
||||
| FunctionPointerFlow.cs:59:9:59:13 | function pointer call | FunctionPointerFlow.cs:64:9:64:23 | call to method M10 | FunctionPointerFlow.cs:24:24:24:25 | M4 |
|
||||
| FunctionPointerFlow.cs:69:9:69:13 | function pointer call | FunctionPointerFlow.cs:81:9:81:29 | call to method M16 | FunctionPointerFlow.cs:72:24:72:26 | M17 |
|
||||
|
||||
@@ -1,5 +1,38 @@
|
||||
import csharp
|
||||
import semmle.code.csharp.dataflow.internal.DataFlowImplCommon
|
||||
import semmle.code.csharp.dataflow.internal.DataFlowDispatch
|
||||
|
||||
query predicate fptrCall(FunctionPointerCall fptrc, Callable c, CallContext::CallContext cc) {
|
||||
c = fptrc.getARuntimeTarget(cc)
|
||||
query predicate fptrCall(FunctionPointerCall dc, Callable c) { c = dc.getARuntimeTarget() }
|
||||
|
||||
private class LocatableDataFlowCallOption extends DataFlowCallOption {
|
||||
Location getLocation() {
|
||||
this = TDataFlowCallNone() and
|
||||
result instanceof EmptyLocation
|
||||
or
|
||||
exists(DataFlowCall call |
|
||||
this = TDataFlowCallSome(call) and
|
||||
result = call.getLocation()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class LocatableDataFlowCall extends TDataFlowCall {
|
||||
LocatableDataFlowCall() {
|
||||
this.(ExplicitDelegateLikeDataFlowCall).getCall() instanceof FunctionPointerCall
|
||||
}
|
||||
|
||||
string toString() { result = this.(DataFlowCall).toString() }
|
||||
|
||||
Location getLocation() {
|
||||
exists(Location l |
|
||||
l = this.(DataFlowCall).getLocation() and
|
||||
if l instanceof SourceLocation then result = l else result instanceof EmptyLocation
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
query predicate fptrCallContext(
|
||||
LocatableDataFlowCall call, LocatableDataFlowCallOption lastCall, DataFlowCallable target
|
||||
) {
|
||||
target = viableCallableLambda(call, lastCall)
|
||||
}
|
||||
|
||||
@@ -52,6 +52,7 @@
|
||||
| GlobalDataFlow.cs:401:15:401:20 | access to local variable sink11 |
|
||||
| GlobalDataFlow.cs:424:41:424:46 | access to local variable sink20 |
|
||||
| GlobalDataFlow.cs:475:15:475:20 | access to local variable sink45 |
|
||||
| GlobalDataFlow.cs:483:32:483:32 | access to parameter s |
|
||||
| Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x |
|
||||
| Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x |
|
||||
| Splitting.cs:11:19:11:19 | access to local variable x |
|
||||
|
||||
@@ -229,6 +229,10 @@ edges
|
||||
| GlobalDataFlow.cs:473:23:473:44 | call to method GetAwaiter [m_task, Result] : String | GlobalDataFlow.cs:474:22:474:28 | access to local variable awaiter [m_task, Result] : String |
|
||||
| GlobalDataFlow.cs:474:22:474:28 | access to local variable awaiter [m_task, Result] : String | GlobalDataFlow.cs:474:22:474:40 | call to method GetResult : String |
|
||||
| GlobalDataFlow.cs:474:22:474:40 | call to method GetResult : String | GlobalDataFlow.cs:475:15:475:20 | access to local variable sink45 |
|
||||
| GlobalDataFlow.cs:480:53:480:55 | arg : String | GlobalDataFlow.cs:484:15:484:17 | access to parameter arg : String |
|
||||
| GlobalDataFlow.cs:483:21:483:21 | s : String | GlobalDataFlow.cs:483:32:483:32 | access to parameter s |
|
||||
| GlobalDataFlow.cs:484:15:484:17 | access to parameter arg : String | GlobalDataFlow.cs:483:21:483:21 | s : String |
|
||||
| GlobalDataFlow.cs:487:27:487:40 | "taint source" : String | GlobalDataFlow.cs:480:53:480:55 | arg : String |
|
||||
| Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:8:24:8:30 | [b (line 3): false] access to parameter tainted : String |
|
||||
| Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:8:24:8:30 | [b (line 3): true] access to parameter tainted : String |
|
||||
| Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return : String | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x |
|
||||
@@ -444,6 +448,11 @@ nodes
|
||||
| GlobalDataFlow.cs:474:22:474:28 | access to local variable awaiter [m_task, Result] : String | semmle.label | access to local variable awaiter [m_task, Result] : String |
|
||||
| GlobalDataFlow.cs:474:22:474:40 | call to method GetResult : String | semmle.label | call to method GetResult : String |
|
||||
| GlobalDataFlow.cs:475:15:475:20 | access to local variable sink45 | semmle.label | access to local variable sink45 |
|
||||
| GlobalDataFlow.cs:480:53:480:55 | arg : String | semmle.label | arg : String |
|
||||
| GlobalDataFlow.cs:483:21:483:21 | s : String | semmle.label | s : String |
|
||||
| GlobalDataFlow.cs:483:32:483:32 | access to parameter s | semmle.label | access to parameter s |
|
||||
| GlobalDataFlow.cs:484:15:484:17 | access to parameter arg : String | semmle.label | access to parameter arg : String |
|
||||
| GlobalDataFlow.cs:487:27:487:40 | "taint source" : String | semmle.label | "taint source" : String |
|
||||
| Splitting.cs:3:28:3:34 | tainted : String | semmle.label | tainted : String |
|
||||
| Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return : String | semmle.label | [b (line 3): false] call to method Return : String |
|
||||
| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : String | semmle.label | [b (line 3): true] call to method Return : String |
|
||||
@@ -520,6 +529,7 @@ nodes
|
||||
| GlobalDataFlow.cs:182:15:182:19 | access to local variable sink9 | GlobalDataFlow.cs:180:35:180:48 | "taint source" : String | GlobalDataFlow.cs:182:15:182:19 | access to local variable sink9 | access to local variable sink9 |
|
||||
| Splitting.cs:11:19:11:19 | access to local variable x | Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:11:19:11:19 | access to local variable x | access to local variable x |
|
||||
| Splitting.cs:34:19:34:19 | access to local variable x | Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:34:19:34:19 | access to local variable x | access to local variable x |
|
||||
| GlobalDataFlow.cs:483:32:483:32 | access to parameter s | GlobalDataFlow.cs:487:27:487:40 | "taint source" : String | GlobalDataFlow.cs:483:32:483:32 | access to parameter s | access to parameter s |
|
||||
| Capture.cs:57:27:57:32 | access to parameter sink39 | Capture.cs:7:20:7:26 | tainted : String | Capture.cs:57:27:57:32 | access to parameter sink39 | access to parameter sink39 |
|
||||
| GlobalDataFlow.cs:257:15:257:24 | access to parameter sinkParam0 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:257:15:257:24 | access to parameter sinkParam0 | access to parameter sinkParam0 |
|
||||
| GlobalDataFlow.cs:262:15:262:24 | access to parameter sinkParam1 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:262:15:262:24 | access to parameter sinkParam1 | access to parameter sinkParam1 |
|
||||
|
||||
@@ -196,7 +196,7 @@
|
||||
| GlobalDataFlow.cs:472:25:472:50 | call to method ConfigureAwait | return | GlobalDataFlow.cs:472:25:472:50 | call to method ConfigureAwait |
|
||||
| GlobalDataFlow.cs:473:23:473:44 | call to method GetAwaiter | return | GlobalDataFlow.cs:473:23:473:44 | call to method GetAwaiter |
|
||||
| GlobalDataFlow.cs:474:22:474:40 | call to method GetResult | return | GlobalDataFlow.cs:474:22:474:40 | call to method GetResult |
|
||||
| GlobalDataFlow.cs:486:44:486:47 | delegate call | return | GlobalDataFlow.cs:486:44:486:47 | delegate call |
|
||||
| GlobalDataFlow.cs:498:44:498:47 | delegate call | return | GlobalDataFlow.cs:498:44:498:47 | delegate call |
|
||||
| Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return | return | Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return |
|
||||
| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return | return | Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return |
|
||||
| Splitting.cs:20:22:20:30 | call to method Return | return | Splitting.cs:20:22:20:30 | call to method Return |
|
||||
|
||||
@@ -474,6 +474,18 @@ public class DataFlow
|
||||
var sink45 = awaiter.GetResult();
|
||||
Check(sink45);
|
||||
}
|
||||
|
||||
void M5(bool b)
|
||||
{
|
||||
void Inner(Action<string> a, bool b, string arg)
|
||||
{
|
||||
if (b)
|
||||
a = s => Check(s);
|
||||
a(arg);
|
||||
}
|
||||
|
||||
Inner(_ => {}, b, "taint source");
|
||||
}
|
||||
}
|
||||
|
||||
static class IEnumerableExtensions
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
| GlobalDataFlow.cs:453:15:453:20 | access to local variable sink43 |
|
||||
| GlobalDataFlow.cs:463:15:463:20 | access to local variable sink44 |
|
||||
| GlobalDataFlow.cs:475:15:475:20 | access to local variable sink45 |
|
||||
| GlobalDataFlow.cs:483:32:483:32 | access to parameter s |
|
||||
| Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x |
|
||||
| Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x |
|
||||
| Splitting.cs:11:19:11:19 | access to local variable x |
|
||||
|
||||
@@ -249,6 +249,10 @@ edges
|
||||
| GlobalDataFlow.cs:473:23:473:44 | call to method GetAwaiter [m_task, Result] : String | GlobalDataFlow.cs:474:22:474:28 | access to local variable awaiter [m_task, Result] : String |
|
||||
| GlobalDataFlow.cs:474:22:474:28 | access to local variable awaiter [m_task, Result] : String | GlobalDataFlow.cs:474:22:474:40 | call to method GetResult : String |
|
||||
| GlobalDataFlow.cs:474:22:474:40 | call to method GetResult : String | GlobalDataFlow.cs:475:15:475:20 | access to local variable sink45 |
|
||||
| GlobalDataFlow.cs:480:53:480:55 | arg : String | GlobalDataFlow.cs:484:15:484:17 | access to parameter arg : String |
|
||||
| GlobalDataFlow.cs:483:21:483:21 | s : String | GlobalDataFlow.cs:483:32:483:32 | access to parameter s |
|
||||
| GlobalDataFlow.cs:484:15:484:17 | access to parameter arg : String | GlobalDataFlow.cs:483:21:483:21 | s : String |
|
||||
| GlobalDataFlow.cs:487:27:487:40 | "taint source" : String | GlobalDataFlow.cs:480:53:480:55 | arg : String |
|
||||
| Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:8:24:8:30 | [b (line 3): false] access to parameter tainted : String |
|
||||
| Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:8:24:8:30 | [b (line 3): true] access to parameter tainted : String |
|
||||
| Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return : String | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x |
|
||||
@@ -486,6 +490,11 @@ nodes
|
||||
| GlobalDataFlow.cs:474:22:474:28 | access to local variable awaiter [m_task, Result] : String | semmle.label | access to local variable awaiter [m_task, Result] : String |
|
||||
| GlobalDataFlow.cs:474:22:474:40 | call to method GetResult : String | semmle.label | call to method GetResult : String |
|
||||
| GlobalDataFlow.cs:475:15:475:20 | access to local variable sink45 | semmle.label | access to local variable sink45 |
|
||||
| GlobalDataFlow.cs:480:53:480:55 | arg : String | semmle.label | arg : String |
|
||||
| GlobalDataFlow.cs:483:21:483:21 | s : String | semmle.label | s : String |
|
||||
| GlobalDataFlow.cs:483:32:483:32 | access to parameter s | semmle.label | access to parameter s |
|
||||
| GlobalDataFlow.cs:484:15:484:17 | access to parameter arg : String | semmle.label | access to parameter arg : String |
|
||||
| GlobalDataFlow.cs:487:27:487:40 | "taint source" : String | semmle.label | "taint source" : String |
|
||||
| Splitting.cs:3:28:3:34 | tainted : String | semmle.label | tainted : String |
|
||||
| Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return : String | semmle.label | [b (line 3): false] call to method Return : String |
|
||||
| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : String | semmle.label | [b (line 3): true] call to method Return : String |
|
||||
@@ -573,6 +582,7 @@ nodes
|
||||
| GlobalDataFlow.cs:453:15:453:20 | access to local variable sink43 | GlobalDataFlow.cs:451:35:451:48 | "taint source" : String | GlobalDataFlow.cs:453:15:453:20 | access to local variable sink43 | access to local variable sink43 |
|
||||
| GlobalDataFlow.cs:463:15:463:20 | access to local variable sink44 | GlobalDataFlow.cs:462:51:462:64 | "taint source" : String | GlobalDataFlow.cs:463:15:463:20 | access to local variable sink44 | access to local variable sink44 |
|
||||
| GlobalDataFlow.cs:475:15:475:20 | access to local variable sink45 | GlobalDataFlow.cs:471:35:471:48 | "taint source" : String | GlobalDataFlow.cs:475:15:475:20 | access to local variable sink45 | access to local variable sink45 |
|
||||
| GlobalDataFlow.cs:483:32:483:32 | access to parameter s | GlobalDataFlow.cs:487:27:487:40 | "taint source" : String | GlobalDataFlow.cs:483:32:483:32 | access to parameter s | access to parameter s |
|
||||
| Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | [b (line 3): false] access to local variable x |
|
||||
| Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | [b (line 3): true] access to local variable x |
|
||||
| Splitting.cs:11:19:11:19 | access to local variable x | Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:11:19:11:19 | access to local variable x | access to local variable x |
|
||||
|
||||
Reference in New Issue
Block a user