mirror of
https://github.com/github/codeql.git
synced 2026-04-28 02:05:14 +02:00
C#: Rework function pointer/delegate call DF
This commit is contained in:
@@ -63,7 +63,7 @@ predicate mayEscape(LocalVariable v) {
|
||||
exists(Callable c, Expr e, Expr succ | c = getACapturingCallableAncestor(v) |
|
||||
e = getADelegateExpr(c) and
|
||||
DataFlow::localExprFlow(e, succ) and
|
||||
not succ = any(DelegateCall dc).getDelegateExpr() and
|
||||
not succ = any(DelegateCall dc).getExpr() and
|
||||
not succ = any(Cast cast).getExpr() and
|
||||
not succ = any(Call call | nonEscapingCall(call)).getAnArgument() and
|
||||
not succ = any(AssignableDefinition ad | ad.getTarget() instanceof LocalVariable).getSource()
|
||||
|
||||
@@ -97,9 +97,7 @@ private class TranslatedDelegateInvokeCall extends TranslatedCompilerGeneratedCa
|
||||
)
|
||||
}
|
||||
|
||||
override TranslatedExprBase getQualifier() {
|
||||
result = getTranslatedExpr(generatedBy.getDelegateExpr())
|
||||
}
|
||||
override TranslatedExprBase getQualifier() { result = getTranslatedExpr(generatedBy.getExpr()) }
|
||||
|
||||
override Instruction getQualifierResult() { result = getQualifier().getResult() }
|
||||
|
||||
|
||||
@@ -11,7 +11,8 @@ cached
|
||||
private newtype TCallContext =
|
||||
TEmptyCallContext() or
|
||||
TArgNonDelegateCallContext(Expr arg) { exists(DispatchCall dc | arg = dc.getArgument(_)) } or
|
||||
TArgDelegateCallContext(DelegateCall dc, int i) { exists(dc.getArgument(i)) }
|
||||
TArgDelegateCallContext(DelegateCall dc, int i) { exists(dc.getArgument(i)) } or
|
||||
TArgFunctionPointerCallContext(FunctionPointerCall fptrc, int i) { exists(fptrc.getArgument(i)) }
|
||||
|
||||
/**
|
||||
* A call context.
|
||||
@@ -60,12 +61,14 @@ class NonDelegateCallArgumentCallContext extends ArgumentCallContext, TArgNonDel
|
||||
override Location getLocation() { result = arg.getLocation() }
|
||||
}
|
||||
|
||||
/** An argument of a delegate call. */
|
||||
class DelegateCallArgumentCallContext extends ArgumentCallContext, TArgDelegateCallContext {
|
||||
DelegateCall dc;
|
||||
/** An argument of a delegate or function pointer call. */
|
||||
class DelegateLikeCallArgumentCallContext extends ArgumentCallContext {
|
||||
DelegateLikeCall dc;
|
||||
int arg;
|
||||
|
||||
DelegateCallArgumentCallContext() { this = TArgDelegateCallContext(dc, arg) }
|
||||
DelegateLikeCallArgumentCallContext() {
|
||||
this = TArgDelegateCallContext(dc, arg) or this = TArgFunctionPointerCallContext(dc, arg)
|
||||
}
|
||||
|
||||
override predicate isArgument(Expr call, int i) {
|
||||
call = dc and
|
||||
@@ -76,3 +79,15 @@ class DelegateCallArgumentCallContext extends ArgumentCallContext, TArgDelegateC
|
||||
|
||||
override Location getLocation() { result = dc.getArgument(arg).getLocation() }
|
||||
}
|
||||
|
||||
/** An argument of a delegate call. */
|
||||
class DelegateCallArgumentCallContext extends DelegateLikeCallArgumentCallContext,
|
||||
TArgDelegateCallContext {
|
||||
DelegateCallArgumentCallContext() { this = TArgDelegateCallContext(dc, arg) }
|
||||
}
|
||||
|
||||
/** An argument of a function pointer call. */
|
||||
class FunctionPointerCallArgumentCallContext extends DelegateLikeCallArgumentCallContext,
|
||||
TArgFunctionPointerCallContext {
|
||||
FunctionPointerCallArgumentCallContext() { this = TArgFunctionPointerCallContext(dc, arg) }
|
||||
}
|
||||
|
||||
@@ -14,8 +14,14 @@ private import semmle.code.csharp.dataflow.FlowSummary
|
||||
private import semmle.code.csharp.dispatch.Dispatch
|
||||
private import semmle.code.csharp.frameworks.system.linq.Expressions
|
||||
|
||||
/** A source of flow for a delegate or function pointer expression. */
|
||||
private class DelegateLikeFlowSource extends DataFlow::ExprNode {
|
||||
/** Gets the callable that is referenced in this delegate or function pointer flow source. */
|
||||
Callable getCallable() { none() }
|
||||
}
|
||||
|
||||
/** A source of flow for a delegate expression. */
|
||||
private class DelegateFlowSource extends DataFlow::ExprNode {
|
||||
private class DelegateFlowSource extends DelegateLikeFlowSource {
|
||||
Callable c;
|
||||
|
||||
DelegateFlowSource() {
|
||||
@@ -27,11 +33,26 @@ private class DelegateFlowSource extends DataFlow::ExprNode {
|
||||
}
|
||||
|
||||
/** Gets the callable that is referenced in this delegate flow source. */
|
||||
Callable getCallable() { result = c }
|
||||
override Callable getCallable() { result = c }
|
||||
}
|
||||
|
||||
/** A sink of flow for a delegate expression. */
|
||||
abstract private class DelegateFlowSink extends DataFlow::Node {
|
||||
/** A source of flow for a function pointer expression. */
|
||||
private class FunctionPointerFlowSource extends DelegateLikeFlowSource {
|
||||
Callable c;
|
||||
|
||||
FunctionPointerFlowSource() {
|
||||
this.getExpr() =
|
||||
any(Expr e |
|
||||
c = e.(AddressOfExpr).getOperand().(CallableAccess).getTarget().getUnboundDeclaration()
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the callable that is referenced in this function pointer flow source. */
|
||||
override Callable getCallable() { result = c }
|
||||
}
|
||||
|
||||
/** A sink of flow for a delegate or function pointer expression. */
|
||||
abstract private class DelegateLikeFlowSink extends DataFlow::Node {
|
||||
/**
|
||||
* Gets an actual run-time target of this delegate call in the given call
|
||||
* context, if any. The call context records the *last* call required to
|
||||
@@ -85,25 +106,41 @@ abstract private class DelegateFlowSink extends DataFlow::Node {
|
||||
*/
|
||||
cached
|
||||
Callable getARuntimeTarget(CallContext context) {
|
||||
exists(DelegateFlowSource dfs |
|
||||
exists(DelegateLikeFlowSource dfs |
|
||||
flowsFrom(this, dfs, _, context) and
|
||||
result = dfs.getCallable()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** A delegate or function pointer call expression. */
|
||||
class DelegateLikeCallExpr extends DelegateLikeFlowSink, DataFlow::ExprNode {
|
||||
/** Gets the delegate or function pointer call that this expression belongs to. */
|
||||
DelegateLikeCall getCall() { none() }
|
||||
}
|
||||
|
||||
/** A delegate call expression. */
|
||||
class DelegateCallExpr extends DelegateFlowSink, DataFlow::ExprNode {
|
||||
class DelegateCallExpr extends DelegateLikeCallExpr {
|
||||
DelegateCall dc;
|
||||
|
||||
DelegateCallExpr() { this.getExpr() = dc.getDelegateExpr() }
|
||||
DelegateCallExpr() { this.getExpr() = dc.getExpr() }
|
||||
|
||||
/** Gets the delegate call that this expression belongs to. */
|
||||
DelegateCall getDelegateCall() { result = dc }
|
||||
override DelegateCall getCall() { result = dc }
|
||||
}
|
||||
|
||||
/** A function pointer call expression. */
|
||||
class FunctionPointerCallExpr extends DelegateLikeCallExpr {
|
||||
FunctionPointerCall fptrc;
|
||||
|
||||
FunctionPointerCallExpr() { this.getExpr() = fptrc.getExpr() }
|
||||
|
||||
/** Gets the function pointer call that this expression belongs to. */
|
||||
override FunctionPointerCall getCall() { result = fptrc }
|
||||
}
|
||||
|
||||
/** A parameter of delegate type belonging to a callable with a flow summary. */
|
||||
class SummaryDelegateParameterSink extends DelegateFlowSink, ParameterNode {
|
||||
class SummaryDelegateParameterSink extends DelegateLikeFlowSink, ParameterNode {
|
||||
SummaryDelegateParameterSink() {
|
||||
this.getType() instanceof SystemLinqExpressions::DelegateExtType and
|
||||
this.isParameterOf(any(SummarizedCallable c), _)
|
||||
@@ -111,7 +148,7 @@ class SummaryDelegateParameterSink extends DelegateFlowSink, ParameterNode {
|
||||
}
|
||||
|
||||
/** A delegate expression that is added to an event. */
|
||||
class AddEventSource extends DelegateFlowSink, DataFlow::ExprNode {
|
||||
class AddEventSource extends DelegateLikeFlowSink, DataFlow::ExprNode {
|
||||
AddEventExpr ae;
|
||||
|
||||
AddEventSource() { this.getExpr() = ae.getRValue() }
|
||||
@@ -150,7 +187,7 @@ private class NormalReturnNode extends Node {
|
||||
* records the last call on the path from `node` to `sink`, if any.
|
||||
*/
|
||||
private predicate flowsFrom(
|
||||
DelegateFlowSink sink, DataFlow::Node node, boolean isReturned, CallContext lastCall
|
||||
DelegateLikeFlowSink sink, DataFlow::Node node, boolean isReturned, CallContext lastCall
|
||||
) {
|
||||
// Base case
|
||||
sink = node and
|
||||
@@ -188,7 +225,8 @@ private predicate flowsFrom(
|
||||
or
|
||||
// Flow into a callable (delegate call)
|
||||
exists(
|
||||
ParameterNode mid, CallContext prevLastCall, DelegateCall call, Callable c, Parameter p, int i
|
||||
ParameterNode mid, CallContext prevLastCall, DelegateLikeCall call, Callable c, Parameter p,
|
||||
int i
|
||||
|
|
||||
flowsFrom(sink, mid, isReturned, prevLastCall) and
|
||||
isReturned = false and
|
||||
@@ -238,14 +276,14 @@ private predicate flowIntoNonDelegateCall(NonDelegateCall call, Expr arg, DotNet
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate flowIntoDelegateCall(DelegateCall call, Callable c, Expr arg, int i) {
|
||||
exists(DelegateFlowSource dfs, DelegateCallExpr dce |
|
||||
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
|
||||
flowsFrom(dce, dfs, _, _) and
|
||||
arg = call.getArgument(i) and
|
||||
c = dfs.getCallable() and
|
||||
call = dce.getDelegateCall()
|
||||
call = dce.getCall()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -255,11 +293,13 @@ private predicate flowOutOfNonDelegateCall(NonDelegateCall call, NormalReturnNod
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate flowOutOfDelegateCall(DelegateCall dc, NormalReturnNode ret, CallContext lastCall) {
|
||||
exists(DelegateFlowSource dfs, DelegateCallExpr dce, Callable c |
|
||||
private predicate flowOutOfDelegateCall(
|
||||
DelegateLikeCall dc, NormalReturnNode ret, CallContext lastCall
|
||||
) {
|
||||
exists(DelegateLikeFlowSource dfs, DelegateLikeCallExpr dce, Callable c |
|
||||
flowsFrom(dce, dfs, _, lastCall) and
|
||||
ret.getEnclosingCallable() = c and
|
||||
c = dfs.getCallable() and
|
||||
dc = dce.getDelegateCall()
|
||||
dc = dce.getCall()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,205 +0,0 @@
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*
|
||||
* Provides classes for resolving function pointer calls.
|
||||
*/
|
||||
|
||||
import csharp
|
||||
private import dotnet
|
||||
private import semmle.code.csharp.dataflow.CallContext
|
||||
private import semmle.code.csharp.dataflow.internal.DataFlowDispatch
|
||||
private import semmle.code.csharp.dataflow.internal.DataFlowPrivate
|
||||
private import semmle.code.csharp.dataflow.internal.DataFlowPublic
|
||||
private import semmle.code.csharp.dataflow.FlowSummary
|
||||
private import semmle.code.csharp.dispatch.Dispatch
|
||||
private import semmle.code.csharp.frameworks.system.linq.Expressions
|
||||
|
||||
/** A source of flow for a function pointer expression. */
|
||||
private class FunctionPointerFlowSource extends DataFlow::ExprNode {
|
||||
Callable c;
|
||||
|
||||
FunctionPointerFlowSource() {
|
||||
this.getExpr() =
|
||||
any(Expr e |
|
||||
c = e.(AddressOfExpr).getOperand().(CallableAccess).getTarget().getUnboundDeclaration()
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the callable that is referenced in this function pointer flow source. */
|
||||
Callable getCallable() { result = c }
|
||||
}
|
||||
|
||||
/** A sink of flow for a function pointer expression. */
|
||||
abstract private class FunctionPointerFlowSink extends DataFlow::Node {
|
||||
/**
|
||||
* Gets an actual run-time target of this function pointer call in the given call
|
||||
* context, if any. The call context records the *last* call required to
|
||||
* resolve the target, if any.
|
||||
*
|
||||
* See examples in `DelegateFlowSink`.
|
||||
*/
|
||||
cached
|
||||
Callable getARuntimeTarget(CallContext context) {
|
||||
exists(FunctionPointerFlowSource fptrfs |
|
||||
flowsFrom(this, fptrfs, _, context) and
|
||||
result = fptrfs.getCallable()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** A function pointer call expression. */
|
||||
class FunctionPointerCallExpr extends FunctionPointerFlowSink, DataFlow::ExprNode {
|
||||
FunctionPointerCall fptrc;
|
||||
|
||||
FunctionPointerCallExpr() { this.getExpr() = fptrc.getFunctionPointerExpr() }
|
||||
|
||||
/** Gets the function pointer call that this expression belongs to. */
|
||||
FunctionPointerCall getFunctionPointerCall() { result = fptrc }
|
||||
}
|
||||
|
||||
/** A non-function pointer call. */
|
||||
private class NonFunctionPointerCall extends Expr {
|
||||
private DispatchCall dc;
|
||||
|
||||
NonFunctionPointerCall() { this = dc.getCall() }
|
||||
|
||||
/**
|
||||
* Gets a run-time target of this call. A target is always a source
|
||||
* declaration, and if the callable has both CIL and source code, only
|
||||
* the source code version is returned.
|
||||
*/
|
||||
Callable getARuntimeTarget() { result = getCallableForDataFlow(dc.getADynamicTarget()) }
|
||||
|
||||
/** Gets the `i`th argument of this call. */
|
||||
Expr getArgument(int i) { result = dc.getArgument(i) }
|
||||
}
|
||||
|
||||
private class NormalReturnNode extends Node {
|
||||
NormalReturnNode() { this.(ReturnNode).getKind() instanceof NormalReturnKind }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow (inter-procedurally) to function pointer `sink` from
|
||||
* `node`. This predicate searches backwards from `sink` to `node`.
|
||||
*
|
||||
* The parameter `isReturned` indicates whether the path from `sink` to
|
||||
* `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(
|
||||
FunctionPointerFlowSink sink, DataFlow::Node node, boolean isReturned, CallContext lastCall
|
||||
) {
|
||||
// Base case
|
||||
sink = node and
|
||||
isReturned = false and
|
||||
lastCall instanceof EmptyCallContext
|
||||
or
|
||||
// Local flow
|
||||
exists(DataFlow::Node mid | flowsFrom(sink, mid, isReturned, lastCall) |
|
||||
LocalFlow::localFlowStepCommon(node, mid)
|
||||
or
|
||||
exists(Ssa::Definition def |
|
||||
LocalFlow::localSsaFlowStep(def, node, mid) and
|
||||
LocalFlow::usesInstanceField(def)
|
||||
)
|
||||
)
|
||||
or
|
||||
// Flow through static field or property
|
||||
exists(DataFlow::Node mid |
|
||||
flowsFrom(sink, mid, _, _) and
|
||||
jumpStep(node, mid) and
|
||||
isReturned = false and
|
||||
lastCall instanceof EmptyCallContext
|
||||
)
|
||||
or
|
||||
// Flow into a callable (non-function pointer call)
|
||||
exists(ParameterNode mid, CallContext prevLastCall, NonFunctionPointerCall call, Parameter p |
|
||||
flowsFrom(sink, mid, isReturned, prevLastCall) and
|
||||
isReturned = false and
|
||||
p = mid.getParameter() and
|
||||
flowIntoNonFunctionPointerCall(call, node.asExpr(), p) and
|
||||
lastCall = getLastCall(prevLastCall, call, p.getPosition())
|
||||
)
|
||||
or
|
||||
// Flow into a callable (function pointer call)
|
||||
exists(
|
||||
ParameterNode mid, CallContext prevLastCall, FunctionPointerCall call, Callable c, Parameter p,
|
||||
int i
|
||||
|
|
||||
flowsFrom(sink, mid, isReturned, prevLastCall) and
|
||||
isReturned = false and
|
||||
flowIntoFunctionPointerCall(call, c, node.asExpr(), i) and
|
||||
c.getParameter(i) = p and
|
||||
p = mid.getParameter() and
|
||||
lastCall = getLastCall(prevLastCall, call, i)
|
||||
)
|
||||
or
|
||||
// Flow out of a callable (non-function pointer call).
|
||||
exists(DataFlow::ExprNode mid |
|
||||
flowsFrom(sink, mid, _, lastCall) and
|
||||
isReturned = true and
|
||||
flowOutOfNonFunctionPointerCall(mid.getExpr(), node)
|
||||
)
|
||||
or
|
||||
// Flow out of a callable (function pointer call).
|
||||
exists(DataFlow::ExprNode mid |
|
||||
flowsFrom(sink, mid, _, _) and
|
||||
isReturned = true and
|
||||
flowOutOfFunctionPointerCall(mid.getExpr(), node, lastCall)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the last call when tracking flow into `call`. The context
|
||||
* `prevLastCall` is the previous last call, so the result is the
|
||||
* previous call if it exists, otherwise `call` is the last call.
|
||||
*/
|
||||
bindingset[call, i]
|
||||
private CallContext getLastCall(CallContext prevLastCall, Expr call, int i) {
|
||||
prevLastCall instanceof EmptyCallContext and
|
||||
result.(ArgumentCallContext).isArgument(call, i)
|
||||
or
|
||||
prevLastCall instanceof ArgumentCallContext and
|
||||
result = prevLastCall
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate flowIntoNonFunctionPointerCall(
|
||||
NonFunctionPointerCall call, Expr arg, DotNet::Parameter p
|
||||
) {
|
||||
exists(DotNet::Callable callable, int i |
|
||||
callable = call.getARuntimeTarget() and
|
||||
p = callable.getAParameter() and
|
||||
arg = call.getArgument(i) and
|
||||
i = p.getPosition()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate flowIntoFunctionPointerCall(FunctionPointerCall call, Callable c, Expr arg, int i) {
|
||||
exists(FunctionPointerFlowSource fptrfs, FunctionPointerCallExpr fptrce |
|
||||
// the call context is irrelevant because the function pointer call
|
||||
// itself will be the context
|
||||
flowsFrom(fptrce, fptrfs, _, _) and
|
||||
arg = call.getArgument(i) and
|
||||
c = fptrfs.getCallable() and
|
||||
call = fptrce.getFunctionPointerCall()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate flowOutOfNonFunctionPointerCall(NonFunctionPointerCall call, NormalReturnNode ret) {
|
||||
call.getARuntimeTarget() = ret.getEnclosingCallable()
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate flowOutOfFunctionPointerCall(
|
||||
FunctionPointerCall call, NormalReturnNode ret, CallContext lastCall
|
||||
) {
|
||||
exists(FunctionPointerFlowSource fptrfs, FunctionPointerCallExpr fptrce, Callable c |
|
||||
flowsFrom(fptrce, fptrfs, _, lastCall) and
|
||||
ret.getEnclosingCallable() = c and
|
||||
c = fptrfs.getCallable() and
|
||||
call = fptrce.getFunctionPointerCall()
|
||||
)
|
||||
}
|
||||
@@ -245,7 +245,7 @@ private module CallGraph {
|
||||
* a library callable and `e` is a delegate argument.
|
||||
*/
|
||||
private predicate delegateCall(Call c, Expr e, boolean libraryDelegateCall) {
|
||||
c = any(DelegateCall dc | e = dc.getDelegateExpr()) and
|
||||
c = any(DelegateCall dc | e = dc.getExpr()) and
|
||||
libraryDelegateCall = false
|
||||
or
|
||||
c.getTarget().fromLibrary() and
|
||||
|
||||
@@ -8,7 +8,6 @@ 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.FunctionPointerDataFlow
|
||||
private import semmle.code.csharp.dispatch.Dispatch
|
||||
private import dotnet
|
||||
|
||||
@@ -528,6 +527,39 @@ class MutatorOperatorCall extends OperatorCall {
|
||||
predicate isPostfix() { mutator_invocation_mode(this, 2) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A function pointer or delegate call.
|
||||
*/
|
||||
abstract class DelegateLikeCall extends Call {
|
||||
override Callable getTarget() { none() }
|
||||
|
||||
/**
|
||||
* Gets a potential run-time target of this delegate or function pointer call in the given
|
||||
* call context `cc`.
|
||||
*/
|
||||
Callable getARuntimeTarget(CallContext::CallContext cc) { none() }
|
||||
|
||||
/**
|
||||
* Gets the delegate or function pointer expression of this call. For example, the
|
||||
* delegate expression of `X()` on line 5 is the access to the field `X` in
|
||||
*
|
||||
* ```csharp
|
||||
* class A {
|
||||
* Action X = () => { };
|
||||
*
|
||||
* void CallX() {
|
||||
* X();
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
Expr getExpr() { result = this.getChild(-1) }
|
||||
|
||||
override Callable getARuntimeTarget() { result = getARuntimeTarget(_) }
|
||||
|
||||
override Expr getRuntimeArgument(int i) { result = getArgument(i) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A delegate call, for example `x()` on line 5 in
|
||||
*
|
||||
@@ -541,16 +573,14 @@ class MutatorOperatorCall extends OperatorCall {
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
class DelegateCall extends Call, @delegate_invocation_expr {
|
||||
override Callable getTarget() { none() }
|
||||
|
||||
class DelegateCall extends DelegateLikeCall, @delegate_invocation_expr {
|
||||
/**
|
||||
* Gets a potential run-time target of this delegate call in the given
|
||||
* call context `cc`.
|
||||
*/
|
||||
Callable getARuntimeTarget(CallContext::CallContext cc) {
|
||||
override Callable getARuntimeTarget(CallContext::CallContext cc) {
|
||||
exists(DelegateCallExpr call |
|
||||
this = call.getDelegateCall() and
|
||||
this = call.getCall() and
|
||||
result = call.getARuntimeTarget(cc)
|
||||
)
|
||||
or
|
||||
@@ -568,7 +598,7 @@ class DelegateCall extends Call, @delegate_invocation_expr {
|
||||
}
|
||||
|
||||
private AddEventSource getAnAddEventSource(Callable enclosingCallable) {
|
||||
this.getDelegateExpr().(EventAccess).getTarget() = result.getEvent() and
|
||||
this.getExpr().(EventAccess).getTarget() = result.getEvent() and
|
||||
enclosingCallable = result.getExpr().getEnclosingCallable()
|
||||
}
|
||||
|
||||
@@ -580,25 +610,12 @@ class DelegateCall extends Call, @delegate_invocation_expr {
|
||||
exists(Callable c | result = getAnAddEventSource(c) | c != this.getEnclosingCallable())
|
||||
}
|
||||
|
||||
override Callable getARuntimeTarget() { result = getARuntimeTarget(_) }
|
||||
|
||||
override Expr getRuntimeArgument(int i) { result = getArgument(i) }
|
||||
|
||||
/**
|
||||
* Gets the delegate expression of this delegate call. For example, the
|
||||
* delegate expression of `X()` on line 5 is the access to the field `X` in
|
||||
* DEPRECATED: use `getExpr` instead.
|
||||
*
|
||||
* ```csharp
|
||||
* class A {
|
||||
* Action X = () => { };
|
||||
*
|
||||
* void CallX() {
|
||||
* X();
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
* Gets the delegate expression of this call.
|
||||
*/
|
||||
Expr getDelegateExpr() { result = this.getChild(-1) }
|
||||
deprecated Expr getDelegateExpr() { result = this.getExpr() }
|
||||
|
||||
override string toString() { result = "delegate call" }
|
||||
|
||||
@@ -616,27 +633,18 @@ class DelegateCall extends Call, @delegate_invocation_expr {
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
class FunctionPointerCall extends Call, @function_pointer_invocation_expr {
|
||||
override Callable getTarget() { none() }
|
||||
|
||||
class FunctionPointerCall extends DelegateLikeCall, @function_pointer_invocation_expr {
|
||||
/**
|
||||
* Gets a potential run-time target of this function pointer call in the given
|
||||
* call context `cc`.
|
||||
*/
|
||||
Callable getARuntimeTarget(CallContext::CallContext cc) {
|
||||
override Callable getARuntimeTarget(CallContext::CallContext cc) {
|
||||
exists(FunctionPointerCallExpr call |
|
||||
this = call.getFunctionPointerCall() and
|
||||
this = call.getCall() and
|
||||
result = call.getARuntimeTarget(cc)
|
||||
)
|
||||
}
|
||||
|
||||
override Callable getARuntimeTarget() { result = getARuntimeTarget(_) }
|
||||
|
||||
override Expr getRuntimeArgument(int i) { result = getArgument(i) }
|
||||
|
||||
/** Gets the function pointer expression of this call. */
|
||||
Expr getFunctionPointerExpr() { result = this.getChild(-1) }
|
||||
|
||||
override string toString() { result = "function pointer call" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "FunctionPointerCall" }
|
||||
|
||||
@@ -78,7 +78,7 @@ predicate depends(ValueOrRefType t, ValueOrRefType u) {
|
||||
or
|
||||
exists(DelegateCall dc, DelegateType dt |
|
||||
dc.getEnclosingCallable().getDeclaringType() = t and
|
||||
dc.getDelegateExpr().getType() = dt and
|
||||
dc.getExpr().getType() = dt and
|
||||
usesType(dt.getUnboundDeclaration(), u)
|
||||
)
|
||||
or
|
||||
|
||||
@@ -116,12 +116,12 @@ class DelegateFlow
|
||||
|
||||
public unsafe void M17()
|
||||
{
|
||||
M16(&M2, (i) => {}); // MISSING: a(0) in M2 is calling this lambda
|
||||
M16(&M2, (i) => { });
|
||||
}
|
||||
|
||||
public unsafe void M18()
|
||||
{
|
||||
delegate*<Action<int>, void> fnptr = &M2;
|
||||
fnptr((i) => {}); // MISSING: a(0) in M2 is calling this lambda
|
||||
fnptr((i) => { });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@ delegateCall
|
||||
| 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 |
|
||||
|
||||
@@ -9,7 +9,7 @@ where
|
||||
m.hasName("MainDelegateAndMethodAccesses") and
|
||||
e.getEnclosingCallable() = m and
|
||||
e.getNumberOfArguments() = 1 and
|
||||
e.getDelegateExpr() = a and
|
||||
e.getExpr() = a and
|
||||
a.getTarget().hasName("cd1") and
|
||||
e.getArgument(0).getValue() = "-40"
|
||||
select m, e, a
|
||||
|
||||
@@ -9,7 +9,7 @@ where
|
||||
m.hasName("MainDelegateAndMethodAccesses") and
|
||||
e.getEnclosingCallable() = m and
|
||||
e.getNumberOfArguments() = 1 and
|
||||
e.getDelegateExpr() = a and
|
||||
e.getExpr() = a and
|
||||
a.getTarget().hasName("cd7") and
|
||||
e.getArgument(0).(AddExpr).getRightOperand().(LocalVariableAccess).getTarget().hasName("x")
|
||||
select m, e, a
|
||||
|
||||
@@ -8,7 +8,7 @@ from Method m, DelegateCall e, LocalVariableAccess a
|
||||
where
|
||||
m.hasName("MainDelegateAndMethodAccesses") and
|
||||
e.getEnclosingCallable() = m and
|
||||
e.getDelegateExpr() = a and
|
||||
e.getExpr() = a and
|
||||
a.getTarget().hasName("cd7") and
|
||||
a.getTarget().getType().(DelegateType).hasQualifiedName("Expressions.D")
|
||||
select m, e, a
|
||||
|
||||
@@ -11,7 +11,7 @@ where
|
||||
e.getTarget().getName() = "Click" and
|
||||
e.getTarget().getDeclaringType() = m.getDeclaringType() and
|
||||
d.getEnclosingCallable() = m and
|
||||
d.getDelegateExpr() = e and
|
||||
d.getExpr() = e and
|
||||
d.getArgument(0) instanceof ThisAccess and
|
||||
d.getArgument(1).(ParameterAccess).getTarget().hasName("e")
|
||||
select m, d, e
|
||||
|
||||
Reference in New Issue
Block a user