mirror of
https://github.com/github/codeql.git
synced 2026-04-25 08:45:14 +02:00
Merge pull request #14295 from hvitved/csharp/lambda-type-flow
C#: Improve lambda dispatch using type flow
This commit is contained in:
@@ -47,6 +47,7 @@ extensions:
|
||||
- ["System.Collections.Generic", "List<>", False, "FindAll", "(System.Predicate<T>)", "", "Argument[this].Element", "ReturnValue", "value", "manual"]
|
||||
- ["System.Collections.Generic", "List<>", False, "FindLast", "(System.Predicate<T>)", "", "Argument[this].Element", "Argument[0].Parameter[0]", "value", "manual"]
|
||||
- ["System.Collections.Generic", "List<>", False, "FindLast", "(System.Predicate<T>)", "", "Argument[this].Element", "ReturnValue", "value", "manual"]
|
||||
- ["System.Collections.Generic", "List<>", False, "ForEach", "(System.Action<T>)", "", "Argument[this].Element", "Argument[0].Parameter[0]", "value", "manual"]
|
||||
- ["System.Collections.Generic", "List<>", False, "GetEnumerator", "()", "", "Argument[this].Element", "ReturnValue.Property[System.Collections.Generic.List<>+Enumerator.Current]", "value", "manual"]
|
||||
- ["System.Collections.Generic", "List<>", False, "GetRange", "(System.Int32,System.Int32)", "", "Argument[this].Element", "ReturnValue.Element", "value", "manual"]
|
||||
- ["System.Collections.Generic", "List<>", False, "InsertRange", "(System.Int32,System.Collections.Generic.IEnumerable<T>)", "", "Argument[1].Element", "Argument[this].Element", "value", "manual"]
|
||||
|
||||
@@ -4,6 +4,7 @@ import csharp
|
||||
private import dotnet
|
||||
private import internal.FlowSummaryImpl as Impl
|
||||
private import internal.DataFlowDispatch as DataFlowDispatch
|
||||
private import Impl::Public::SummaryComponent as SummaryComponentInternal
|
||||
|
||||
class ParameterPosition = DataFlowDispatch::ParameterPosition;
|
||||
|
||||
@@ -18,8 +19,6 @@ class SummaryComponent = Impl::Public::SummaryComponent;
|
||||
|
||||
/** Provides predicates for constructing summary components. */
|
||||
module SummaryComponent {
|
||||
private import Impl::Public::SummaryComponent as SummaryComponentInternal
|
||||
|
||||
predicate content = SummaryComponentInternal::content/1;
|
||||
|
||||
/** Gets a summary component for parameter `i`. */
|
||||
@@ -155,3 +154,45 @@ private class RecordConstructorFlowRequiredSummaryComponentStack extends Require
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class Provenance = Impl::Public::Provenance;
|
||||
|
||||
private import semmle.code.csharp.frameworks.system.linq.Expressions
|
||||
|
||||
private SummaryComponent delegateSelf() {
|
||||
exists(ArgumentPosition pos |
|
||||
result = SummaryComponentInternal::parameter(pos) and
|
||||
pos.isDelegateSelf()
|
||||
)
|
||||
}
|
||||
|
||||
private predicate mayInvokeCallback(Callable c, int n) {
|
||||
c.getParameter(n).getType() instanceof SystemLinqExpressions::DelegateExtType and
|
||||
not c.fromSource()
|
||||
}
|
||||
|
||||
private class SummarizedCallableWithCallback extends SummarizedCallable {
|
||||
private int pos;
|
||||
|
||||
SummarizedCallableWithCallback() { mayInvokeCallback(this, pos) }
|
||||
|
||||
override predicate propagatesFlow(
|
||||
SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue
|
||||
) {
|
||||
input = SummaryComponentStack::argument(pos) and
|
||||
output = SummaryComponentStack::push(delegateSelf(), input) and
|
||||
preservesValue = true
|
||||
}
|
||||
|
||||
override predicate hasProvenance(Provenance provenance) { provenance = "hq-generated" }
|
||||
}
|
||||
|
||||
private class RequiredComponentStackForCallback extends RequiredSummaryComponentStack {
|
||||
override predicate required(SummaryComponent head, SummaryComponentStack tail) {
|
||||
exists(int pos |
|
||||
mayInvokeCallback(_, pos) and
|
||||
head = delegateSelf() and
|
||||
tail = SummaryComponentStack::argument(pos)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,13 +136,15 @@ private module Cached {
|
||||
newtype TParameterPosition =
|
||||
TPositionalParameterPosition(int i) { i = any(Parameter p).getPosition() } or
|
||||
TThisParameterPosition() or
|
||||
TImplicitCapturedParameterPosition(LocalScopeVariable v) { capturedWithFlowIn(v) }
|
||||
TImplicitCapturedParameterPosition(LocalScopeVariable v) { capturedWithFlowIn(v) } or
|
||||
TDelegateSelfParameterPosition()
|
||||
|
||||
cached
|
||||
newtype TArgumentPosition =
|
||||
TPositionalArgumentPosition(int i) { i = any(Parameter p).getPosition() } or
|
||||
TQualifierArgumentPosition() or
|
||||
TImplicitCapturedArgumentPosition(LocalScopeVariable v) { capturedWithFlowIn(v) }
|
||||
TImplicitCapturedArgumentPosition(LocalScopeVariable v) { capturedWithFlowIn(v) } or
|
||||
TDelegateSelfArgumentPosition()
|
||||
}
|
||||
|
||||
import Cached
|
||||
@@ -480,6 +482,14 @@ class ParameterPosition extends TParameterPosition {
|
||||
this = TImplicitCapturedParameterPosition(v)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this position represents a reference to a delegate itself.
|
||||
*
|
||||
* Used for tracking flow through captured variables and for improving
|
||||
* delegate dispatch.
|
||||
*/
|
||||
predicate isDelegateSelf() { this = TDelegateSelfParameterPosition() }
|
||||
|
||||
/** Gets a textual representation of this position. */
|
||||
string toString() {
|
||||
result = "position " + this.getPosition()
|
||||
@@ -489,6 +499,9 @@ class ParameterPosition extends TParameterPosition {
|
||||
exists(LocalScopeVariable v |
|
||||
this.isImplicitCapturedParameterPosition(v) and result = "captured " + v
|
||||
)
|
||||
or
|
||||
this.isDelegateSelf() and
|
||||
result = "delegate self"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -505,6 +518,14 @@ class ArgumentPosition extends TArgumentPosition {
|
||||
this = TImplicitCapturedArgumentPosition(v)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this position represents a reference to a delegate itself.
|
||||
*
|
||||
* Used for tracking flow through captured variables and for improving
|
||||
* delegate dispatch.
|
||||
*/
|
||||
predicate isDelegateSelf() { this = TDelegateSelfArgumentPosition() }
|
||||
|
||||
/** Gets a textual representation of this position. */
|
||||
string toString() {
|
||||
result = "position " + this.getPosition()
|
||||
@@ -514,6 +535,9 @@ class ArgumentPosition extends TArgumentPosition {
|
||||
exists(LocalScopeVariable v |
|
||||
this.isImplicitCapturedArgumentPosition(v) and result = "captured " + v
|
||||
)
|
||||
or
|
||||
this.isDelegateSelf() and
|
||||
result = "delegate self"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -527,4 +551,6 @@ predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) {
|
||||
ppos.isImplicitCapturedParameterPosition(v) and
|
||||
apos.isImplicitCapturedArgumentPosition(v)
|
||||
)
|
||||
or
|
||||
ppos.isDelegateSelf() and apos.isDelegateSelf()
|
||||
}
|
||||
|
||||
@@ -45,9 +45,9 @@ abstract class NodeImpl extends Node {
|
||||
abstract DotNet::Type getTypeImpl();
|
||||
|
||||
/** Gets the type of this node used for type pruning. */
|
||||
Gvn::GvnType getDataFlowType() {
|
||||
DataFlowType getDataFlowType() {
|
||||
forceCachingInSameStage() and
|
||||
exists(Type t0 | result = Gvn::getGlobalValueNumber(t0) |
|
||||
exists(Type t0 | result.asGvnType() = Gvn::getGlobalValueNumber(t0) |
|
||||
t0 = getCSharpType(this.getType())
|
||||
or
|
||||
not exists(getCSharpType(this.getType())) and
|
||||
@@ -557,6 +557,8 @@ module LocalFlow {
|
||||
exists(SsaImpl::getAReadAtNode(def, node2.(ExprNode).getControlFlowNode()))
|
||||
)
|
||||
or
|
||||
delegateCreationStep(node1, node2)
|
||||
or
|
||||
node1 =
|
||||
unique(FlowSummaryNode n1 |
|
||||
FlowSummaryImpl::Private::Steps::summaryLocalStep(n1.getSummaryNode(),
|
||||
@@ -793,16 +795,16 @@ private Type getCSharpType(DotNet::Type t) {
|
||||
result.matchesHandle(t)
|
||||
}
|
||||
|
||||
private class RelevantDataFlowType extends DataFlowType {
|
||||
RelevantDataFlowType() { this = any(NodeImpl n).getDataFlowType() }
|
||||
private class RelevantGvnType extends Gvn::GvnType {
|
||||
RelevantGvnType() { this = any(NodeImpl n).getDataFlowType().asGvnType() }
|
||||
}
|
||||
|
||||
/** A GVN type that is either a `DataFlowType` or unifiable with a `DataFlowType`. */
|
||||
private class DataFlowTypeOrUnifiable extends Gvn::GvnType {
|
||||
pragma[nomagic]
|
||||
DataFlowTypeOrUnifiable() {
|
||||
this instanceof RelevantDataFlowType or
|
||||
Gvn::unifiable(any(RelevantDataFlowType t), this)
|
||||
this instanceof RelevantGvnType or
|
||||
Gvn::unifiable(any(RelevantGvnType t), this)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -813,7 +815,7 @@ private TypeParameter getATypeParameterSubType(DataFlowTypeOrUnifiable t) {
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private TypeParameter getATypeParameterSubTypeRestricted(RelevantDataFlowType t) {
|
||||
private TypeParameter getATypeParameterSubTypeRestricted(RelevantGvnType t) {
|
||||
result = getATypeParameterSubType(t)
|
||||
}
|
||||
|
||||
@@ -829,7 +831,7 @@ private Gvn::GvnType getANonTypeParameterSubType(DataFlowTypeOrUnifiable t) {
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private Gvn::GvnType getANonTypeParameterSubTypeRestricted(RelevantDataFlowType t) {
|
||||
private Gvn::GvnType getANonTypeParameterSubTypeRestricted(RelevantGvnType t) {
|
||||
result = getANonTypeParameterSubType(t)
|
||||
}
|
||||
|
||||
@@ -866,6 +868,7 @@ private module Cached {
|
||||
c = any(DataFlowCallable dfc).asCallable() and
|
||||
not c.(Modifiable).isStatic()
|
||||
} or
|
||||
TDelegateSelfReferenceNode(Callable c) { lambdaCreationExpr(_, c) } or
|
||||
TYieldReturnNode(ControlFlow::Nodes::ElementNode cfn) {
|
||||
any(Callable c).canYieldReturn(cfn.getAstNode())
|
||||
} or
|
||||
@@ -949,7 +952,7 @@ private module Cached {
|
||||
TSyntheticFieldApproxContent()
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate commonSubTypeGeneral(DataFlowTypeOrUnifiable t1, RelevantDataFlowType t2) {
|
||||
private predicate commonSubTypeGeneral(DataFlowTypeOrUnifiable t1, RelevantGvnType t2) {
|
||||
not t1 instanceof Gvn::TypeParameterGvnType and
|
||||
t1 = t2
|
||||
or
|
||||
@@ -963,17 +966,20 @@ private module Cached {
|
||||
* `t2` are allowed to be type parameters.
|
||||
*/
|
||||
cached
|
||||
predicate commonSubType(RelevantDataFlowType t1, RelevantDataFlowType t2) {
|
||||
commonSubTypeGeneral(t1, t2)
|
||||
}
|
||||
predicate commonSubType(RelevantGvnType t1, RelevantGvnType t2) { commonSubTypeGeneral(t1, t2) }
|
||||
|
||||
cached
|
||||
predicate commonSubTypeUnifiableLeft(RelevantDataFlowType t1, RelevantDataFlowType t2) {
|
||||
predicate commonSubTypeUnifiableLeft(RelevantGvnType t1, RelevantGvnType t2) {
|
||||
exists(Gvn::GvnType t |
|
||||
Gvn::unifiable(t1, t) and
|
||||
commonSubTypeGeneral(t, t2)
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
newtype TDataFlowType =
|
||||
TGvnDataFlowType(Gvn::GvnType t) or
|
||||
TDelegateDataFlowType(Callable lambda) { lambdaCreationExpr(_, lambda) }
|
||||
}
|
||||
|
||||
import Cached
|
||||
@@ -1119,6 +1125,37 @@ private module ParameterNodes {
|
||||
override string toStringImpl() { result = "this" }
|
||||
}
|
||||
|
||||
/**
|
||||
* The value of a delegate itself at function entry, viewed as a node in a data
|
||||
* flow graph.
|
||||
*
|
||||
* This is used for improving lambda dispatch, and will eventually also be
|
||||
* used for tracking flow through captured variables.
|
||||
*/
|
||||
private class DelegateSelfReferenceNode extends ParameterNodeImpl, TDelegateSelfReferenceNode {
|
||||
private Callable callable;
|
||||
|
||||
DelegateSelfReferenceNode() { this = TDelegateSelfReferenceNode(callable) }
|
||||
|
||||
final Callable getCallable() { result = callable }
|
||||
|
||||
override predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
|
||||
callable = c.asCallable() and pos.isDelegateSelf()
|
||||
}
|
||||
|
||||
override ControlFlow::Node getControlFlowNodeImpl() { none() }
|
||||
|
||||
override DataFlowCallable getEnclosingCallableImpl() { result.asCallable() = callable }
|
||||
|
||||
override Location getLocationImpl() { result = callable.getLocation() }
|
||||
|
||||
override DotNet::Type getTypeImpl() { none() }
|
||||
|
||||
override DataFlowType getDataFlowType() { callable = result.asDelegate() }
|
||||
|
||||
override string toStringImpl() { result = "delegate self in " + callable }
|
||||
}
|
||||
|
||||
/** An implicit entry definition for a captured variable. */
|
||||
class SsaCapturedEntryDefinition extends Ssa::ImplicitEntryDefinition {
|
||||
private LocalScopeVariable v;
|
||||
@@ -1232,6 +1269,18 @@ private module ArgumentNodes {
|
||||
}
|
||||
}
|
||||
|
||||
/** A data-flow node that represents a delegate passed into itself. */
|
||||
class DelegateSelfArgumentNode extends ArgumentNodeImpl {
|
||||
private DataFlowCall call_;
|
||||
|
||||
DelegateSelfArgumentNode() { lambdaCallExpr(call_, this) }
|
||||
|
||||
override predicate argumentOf(DataFlowCall call, ArgumentPosition pos) {
|
||||
call = call_ and
|
||||
pos.isDelegateSelf()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The value of a captured variable as an implicit argument of a call, viewed
|
||||
* as a node in a data flow graph.
|
||||
@@ -1985,41 +2034,92 @@ predicate isUnreachableInCall(Node n, DataFlowCall call) {
|
||||
* For example, `Func<T, int>` and `Func<S, int>` are mapped to the same
|
||||
* `DataFlowType`, while `Func<T, int>` and `Func<string, int>` are not, because
|
||||
* `string` is not a type parameter.
|
||||
*
|
||||
* For delegates, we use the delegate itself instead of its type, in order to
|
||||
* improve dispatch.
|
||||
*/
|
||||
class DataFlowType = Gvn::GvnType;
|
||||
class DataFlowType extends TDataFlowType {
|
||||
Gvn::GvnType asGvnType() { this = TGvnDataFlowType(result) }
|
||||
|
||||
Callable asDelegate() { this = TDelegateDataFlowType(result) }
|
||||
|
||||
/**
|
||||
* Gets an expression that creates a delegate of this type.
|
||||
*
|
||||
* For methods used as method groups in calls there can be multiple
|
||||
* creations associated with the same type.
|
||||
*/
|
||||
Expr getADelegateCreation() {
|
||||
exists(Callable callable |
|
||||
lambdaCreationExpr(result, callable) and
|
||||
this = TDelegateDataFlowType(callable)
|
||||
)
|
||||
}
|
||||
|
||||
final string toString() {
|
||||
result = this.asGvnType().toString()
|
||||
or
|
||||
result = this.asDelegate().toString()
|
||||
}
|
||||
}
|
||||
|
||||
/** Gets the type of `n` used for type pruning. */
|
||||
Gvn::GvnType getNodeType(Node n) { result = n.(NodeImpl).getDataFlowType() }
|
||||
DataFlowType getNodeType(Node n) {
|
||||
result = n.(NodeImpl).getDataFlowType() and
|
||||
not lambdaCreation(n, _, _) and
|
||||
not delegateCreationStep(_, n)
|
||||
or
|
||||
exists(Node arg |
|
||||
delegateCreationStep(arg, n) and
|
||||
result = getNodeType(arg)
|
||||
)
|
||||
or
|
||||
n.asExpr() = result.getADelegateCreation()
|
||||
}
|
||||
|
||||
/** Gets a string representation of a `DataFlowType`. */
|
||||
string ppReprType(DataFlowType t) { result = t.toString() }
|
||||
|
||||
private class DataFlowNullType extends DataFlowType {
|
||||
private class DataFlowNullType extends Gvn::GvnType {
|
||||
DataFlowNullType() { this = Gvn::getGlobalValueNumber(any(NullType nt)) }
|
||||
|
||||
pragma[noinline]
|
||||
predicate isConvertibleTo(DataFlowType t) {
|
||||
predicate isConvertibleTo(Gvn::GvnType t) {
|
||||
defaultNullConversion(_, any(Type t0 | t = Gvn::getGlobalValueNumber(t0)))
|
||||
}
|
||||
}
|
||||
|
||||
private class DataFlowUnknownType extends DataFlowType {
|
||||
DataFlowUnknownType() { this = Gvn::getGlobalValueNumber(any(UnknownType ut)) }
|
||||
}
|
||||
|
||||
private predicate uselessTypebound(DataFlowType t) {
|
||||
t instanceof DataFlowUnknownType or
|
||||
t instanceof Gvn::TypeParameterGvnType
|
||||
private class GvnUnknownType extends Gvn::GvnType {
|
||||
GvnUnknownType() { this = Gvn::getGlobalValueNumber(any(UnknownType ut)) }
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate typeStrongerThan(DataFlowType t1, DataFlowType t2) {
|
||||
t1 != t2 and
|
||||
t1 = getANonTypeParameterSubTypeRestricted(t2)
|
||||
or
|
||||
t1 instanceof RelevantDataFlowType and
|
||||
not uselessTypebound(t1) and
|
||||
uselessTypebound(t2)
|
||||
private predicate uselessTypebound(DataFlowType dt) {
|
||||
dt.asGvnType() =
|
||||
any(Gvn::GvnType t |
|
||||
t instanceof GvnUnknownType or
|
||||
t instanceof Gvn::TypeParameterGvnType
|
||||
)
|
||||
}
|
||||
|
||||
pragma[inline]
|
||||
private predicate compatibleTypesDelegateLeft(DataFlowType dt1, DataFlowType dt2) {
|
||||
exists(Gvn::GvnType t1, Gvn::GvnType t2 |
|
||||
t1 = exprNode(dt1.getADelegateCreation()).(NodeImpl).getDataFlowType().asGvnType() and
|
||||
t2 = dt2.asGvnType()
|
||||
|
|
||||
commonSubType(t1, t2)
|
||||
or
|
||||
commonSubTypeUnifiableLeft(t1, t2)
|
||||
or
|
||||
commonSubTypeUnifiableLeft(t2, t1)
|
||||
or
|
||||
t2.(DataFlowNullType).isConvertibleTo(t1)
|
||||
or
|
||||
t2 instanceof Gvn::TypeParameterGvnType
|
||||
or
|
||||
t2 instanceof GvnUnknownType
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2027,24 +2127,47 @@ predicate typeStrongerThan(DataFlowType t1, DataFlowType t2) {
|
||||
* a node of type `t1` to a node of type `t2`.
|
||||
*/
|
||||
pragma[inline]
|
||||
predicate compatibleTypes(DataFlowType t1, DataFlowType t2) {
|
||||
commonSubType(t1, t2)
|
||||
predicate compatibleTypes(DataFlowType dt1, DataFlowType dt2) {
|
||||
exists(Gvn::GvnType t1, Gvn::GvnType t2 |
|
||||
t1 = dt1.asGvnType() and
|
||||
t2 = dt2.asGvnType()
|
||||
|
|
||||
commonSubType(t1, t2)
|
||||
or
|
||||
commonSubTypeUnifiableLeft(t1, t2)
|
||||
or
|
||||
commonSubTypeUnifiableLeft(t2, t1)
|
||||
or
|
||||
t1.(DataFlowNullType).isConvertibleTo(t2)
|
||||
or
|
||||
t2.(DataFlowNullType).isConvertibleTo(t1)
|
||||
or
|
||||
t1 instanceof Gvn::TypeParameterGvnType
|
||||
or
|
||||
t2 instanceof Gvn::TypeParameterGvnType
|
||||
or
|
||||
t1 instanceof GvnUnknownType
|
||||
or
|
||||
t2 instanceof GvnUnknownType
|
||||
)
|
||||
or
|
||||
commonSubTypeUnifiableLeft(t1, t2)
|
||||
compatibleTypesDelegateLeft(dt1, dt2)
|
||||
or
|
||||
commonSubTypeUnifiableLeft(t2, t1)
|
||||
compatibleTypesDelegateLeft(dt2, dt1)
|
||||
or
|
||||
t1.(DataFlowNullType).isConvertibleTo(t2)
|
||||
dt1.asDelegate() = dt2.asDelegate()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate typeStrongerThan(DataFlowType t1, DataFlowType t2) {
|
||||
t1 != t2 and
|
||||
t1.asGvnType() = getANonTypeParameterSubTypeRestricted(t2.asGvnType())
|
||||
or
|
||||
t2.(DataFlowNullType).isConvertibleTo(t1)
|
||||
t1.asGvnType() instanceof RelevantGvnType and
|
||||
not uselessTypebound(t1) and
|
||||
uselessTypebound(t2)
|
||||
or
|
||||
t1 instanceof Gvn::TypeParameterGvnType
|
||||
or
|
||||
t2 instanceof Gvn::TypeParameterGvnType
|
||||
or
|
||||
t1 instanceof DataFlowUnknownType
|
||||
or
|
||||
t2 instanceof DataFlowUnknownType
|
||||
compatibleTypesDelegateLeft(t1, t2)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2216,17 +2339,20 @@ int accessPathLimit() { result = 5 }
|
||||
*/
|
||||
predicate forceHighPrecision(Content c) { c instanceof ElementContent }
|
||||
|
||||
private predicate lambdaCreationExpr(Expr creation, Callable c) {
|
||||
c =
|
||||
[
|
||||
creation.(AnonymousFunctionExpr),
|
||||
creation.(CallableAccess).getTarget().getUnboundDeclaration(),
|
||||
creation.(AddressOfExpr).getOperand().(CallableAccess).getTarget().getUnboundDeclaration()
|
||||
]
|
||||
}
|
||||
|
||||
class LambdaCallKind = Unit;
|
||||
|
||||
/** Holds if `creation` is an expression that creates a delegate for `c`. */
|
||||
predicate lambdaCreation(Node creation, LambdaCallKind kind, DataFlowCallable c) {
|
||||
exists(Expr e | e = creation.asExpr() |
|
||||
c.asCallable() =
|
||||
[
|
||||
e.(AnonymousFunctionExpr), e.(CallableAccess).getTarget().getUnboundDeclaration(),
|
||||
e.(AddressOfExpr).getOperand().(CallableAccess).getTarget().getUnboundDeclaration()
|
||||
]
|
||||
) and
|
||||
lambdaCreationExpr(creation.asExpr(), c.asCallable()) and
|
||||
exists(kind)
|
||||
}
|
||||
|
||||
@@ -2248,19 +2374,29 @@ private class LambdaConfiguration extends ControlFlowReachabilityConfiguration {
|
||||
}
|
||||
}
|
||||
|
||||
private predicate lambdaCallExpr(DataFlowCall call, ExprNode receiver) {
|
||||
exists(LambdaConfiguration x, DelegateLikeCall dc |
|
||||
x.hasExprPath(dc.getExpr(), receiver.getControlFlowNode(), dc, call.getControlFlowNode())
|
||||
)
|
||||
}
|
||||
|
||||
/** 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())
|
||||
)
|
||||
lambdaCallExpr(call, receiver)
|
||||
or
|
||||
receiver.(FlowSummaryNode).getSummaryNode() = call.(SummaryCall).getReceiver()
|
||||
) and
|
||||
exists(kind)
|
||||
}
|
||||
|
||||
private predicate delegateCreationStep(Node nodeFrom, Node nodeTo) {
|
||||
exists(LambdaConfiguration x, DelegateCreation dc |
|
||||
x.hasExprPath(dc.getArgument(), nodeFrom.(ExprNode).getControlFlowNode(), dc,
|
||||
nodeTo.(ExprNode).getControlFlowNode())
|
||||
)
|
||||
}
|
||||
|
||||
/** Extra data-flow steps needed for lambda flow analysis. */
|
||||
predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preservesValue) {
|
||||
exists(SsaImpl::DefinitionExt def |
|
||||
@@ -2269,11 +2405,8 @@ predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preserves
|
||||
preservesValue = true
|
||||
)
|
||||
or
|
||||
exists(LambdaConfiguration x, DelegateCreation dc |
|
||||
x.hasExprPath(dc.getArgument(), nodeFrom.(ExprNode).getControlFlowNode(), dc,
|
||||
nodeTo.(ExprNode).getControlFlowNode()) and
|
||||
preservesValue = false
|
||||
)
|
||||
delegateCreationStep(nodeFrom, nodeTo) and
|
||||
preservesValue = true
|
||||
or
|
||||
exists(AddEventExpr aee |
|
||||
nodeFrom.asExpr() = aee.getRValue() and
|
||||
|
||||
@@ -35,14 +35,14 @@ private module SyntheticGlobals {
|
||||
DataFlowCallable inject(SummarizedCallable c) { result.asSummarizedCallable() = c }
|
||||
|
||||
/** Gets the parameter position of the instance parameter. */
|
||||
ArgumentPosition callbackSelfParameterPosition() { none() } // disables implicit summary flow to `this` for callbacks
|
||||
ArgumentPosition callbackSelfParameterPosition() { result.isDelegateSelf() }
|
||||
|
||||
/** Gets the synthesized data-flow call for `receiver`. */
|
||||
SummaryCall summaryDataFlowCall(SummaryNode receiver) { receiver = result.getReceiver() }
|
||||
|
||||
/** Gets the type of content `c`. */
|
||||
DataFlowType getContentType(Content c) {
|
||||
exists(Type t | result = Gvn::getGlobalValueNumber(t) |
|
||||
exists(Type t | result.asGvnType() = Gvn::getGlobalValueNumber(t) |
|
||||
t = c.(FieldContent).getField().getType()
|
||||
or
|
||||
t = c.(PropertyContent).getProperty().getType()
|
||||
@@ -56,7 +56,7 @@ DataFlowType getContentType(Content c) {
|
||||
|
||||
/** Gets the type of the parameter at the given position. */
|
||||
DataFlowType getParameterType(SummarizedCallable c, ParameterPosition pos) {
|
||||
exists(Type t | result = Gvn::getGlobalValueNumber(t) |
|
||||
exists(Type t | result.asGvnType() = Gvn::getGlobalValueNumber(t) |
|
||||
exists(int i |
|
||||
pos.getPosition() = i and
|
||||
t = c.getParameter(i).getType()
|
||||
@@ -69,7 +69,7 @@ DataFlowType getParameterType(SummarizedCallable c, ParameterPosition pos) {
|
||||
|
||||
/** Gets the return type of kind `rk` for callable `c`. */
|
||||
DataFlowType getReturnType(DotNet::Callable c, ReturnKind rk) {
|
||||
exists(Type t | result = Gvn::getGlobalValueNumber(t) |
|
||||
exists(Type t | result.asGvnType() = Gvn::getGlobalValueNumber(t) |
|
||||
rk instanceof NormalReturnKind and
|
||||
(
|
||||
t = c.(Constructor).getDeclaringType()
|
||||
@@ -88,10 +88,13 @@ DataFlowType getReturnType(DotNet::Callable c, ReturnKind rk) {
|
||||
*/
|
||||
DataFlowType getCallbackParameterType(DataFlowType t, ArgumentPosition pos) {
|
||||
exists(SystemLinqExpressions::DelegateExtType dt |
|
||||
t = Gvn::getGlobalValueNumber(dt) and
|
||||
result =
|
||||
t.asGvnType() = Gvn::getGlobalValueNumber(dt) and
|
||||
result.asGvnType() =
|
||||
Gvn::getGlobalValueNumber(dt.getDelegateType().getParameter(pos.getPosition()).getType())
|
||||
)
|
||||
or
|
||||
pos.isDelegateSelf() and
|
||||
result = t
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -101,15 +104,15 @@ DataFlowType getCallbackParameterType(DataFlowType t, ArgumentPosition pos) {
|
||||
DataFlowType getCallbackReturnType(DataFlowType t, ReturnKind rk) {
|
||||
rk instanceof NormalReturnKind and
|
||||
exists(SystemLinqExpressions::DelegateExtType dt |
|
||||
t = Gvn::getGlobalValueNumber(dt) and
|
||||
result = Gvn::getGlobalValueNumber(dt.getDelegateType().getReturnType())
|
||||
t.asGvnType() = Gvn::getGlobalValueNumber(dt) and
|
||||
result.asGvnType() = Gvn::getGlobalValueNumber(dt.getDelegateType().getReturnType())
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the type of synthetic global `sg`. */
|
||||
DataFlowType getSyntheticGlobalType(SummaryComponent::SyntheticGlobal sg) {
|
||||
exists(sg) and
|
||||
result = Gvn::getGlobalValueNumber(any(ObjectType t))
|
||||
result.asGvnType() = Gvn::getGlobalValueNumber(any(ObjectType t))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -223,6 +226,9 @@ string getParameterPosition(ParameterPosition pos) {
|
||||
or
|
||||
pos.isThisParameter() and
|
||||
result = "this"
|
||||
or
|
||||
pos.isDelegateSelf() and
|
||||
result = "delegate-self"
|
||||
}
|
||||
|
||||
/** Gets the textual representation of an argument position in the format used for flow summaries. */
|
||||
@@ -231,6 +237,9 @@ string getArgumentPosition(ArgumentPosition pos) {
|
||||
or
|
||||
pos.isQualifier() and
|
||||
result = "this"
|
||||
or
|
||||
pos.isDelegateSelf() and
|
||||
result = "delegate-self"
|
||||
}
|
||||
|
||||
/** Holds if input specification component `c` needs a reference. */
|
||||
@@ -312,6 +321,9 @@ ArgumentPosition parseParamBody(string s) {
|
||||
or
|
||||
s = "this" and
|
||||
result.isQualifier()
|
||||
or
|
||||
s = "delegate-self" and
|
||||
result.isDelegateSelf()
|
||||
}
|
||||
|
||||
/** Gets the parameter position obtained by parsing `X` in `Argument[X]`. */
|
||||
@@ -321,4 +333,7 @@ ParameterPosition parseArgBody(string s) {
|
||||
or
|
||||
s = "this" and
|
||||
result.isThisParameter()
|
||||
or
|
||||
s = "delegate-self" and
|
||||
result.isDelegateSelf()
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,99 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
public class A
|
||||
{
|
||||
static T Source<T>(T source) => throw null;
|
||||
|
||||
public static void Sink<T>(T t) { }
|
||||
|
||||
static void Apply1<T>(Action<T> f, T x)
|
||||
{
|
||||
f(x);
|
||||
}
|
||||
|
||||
static void ApplyWrap1<T>(Action<T> f, T x)
|
||||
{
|
||||
Apply1(f, x);
|
||||
}
|
||||
|
||||
void TestLambdaDispatch1()
|
||||
{
|
||||
ApplyWrap1(x => { Sink(x); }, Source("A")); // $ hasValueFlow=A
|
||||
ApplyWrap1(x => { Sink(x); }, "B"); // no flow
|
||||
ApplyWrap1(x => { }, Source("C"));
|
||||
ApplyWrap1(x => { }, "D");
|
||||
}
|
||||
|
||||
void ListForEachWrap<T>(List<T> l, Action<T> f)
|
||||
{
|
||||
l.ForEach(f);
|
||||
}
|
||||
|
||||
void TestLambdaDispatch2()
|
||||
{
|
||||
var tainted = new List<string> { Source("E") };
|
||||
var safe = new List<string>();
|
||||
ListForEachWrap(safe, x => { Sink(x); }); // no flow
|
||||
ListForEachWrap(tainted, x => { Sink(x); }); // $ hasValueFlow=E
|
||||
}
|
||||
|
||||
static void Apply2<T>(Action<T> f, T x)
|
||||
{
|
||||
f(x);
|
||||
}
|
||||
|
||||
static void ApplyWrap2<T>(Action<T> f, T x)
|
||||
{
|
||||
Apply2(f, x);
|
||||
}
|
||||
|
||||
void SinkMethodGroup1<T>(T t) => Sink(t); // $ hasValueFlow=F $ hasValueFlow=G
|
||||
void SinkMethodGroup2<T>(T t) => Sink(t);
|
||||
|
||||
void TestLambdaDispatch3()
|
||||
{
|
||||
ApplyWrap2(SinkMethodGroup1, Source("F"));
|
||||
ApplyWrap2(SinkMethodGroup2, "B");
|
||||
}
|
||||
|
||||
void ForEach<T>(List<T> l, Action<T> f)
|
||||
{
|
||||
foreach (var x in l)
|
||||
f(x);
|
||||
}
|
||||
|
||||
void ForEachWrap<T>(List<T> l, Action<T> f)
|
||||
{
|
||||
ForEach(l, f);
|
||||
}
|
||||
|
||||
void TestLambdaDispatch4()
|
||||
{
|
||||
var tainted = new List<string> { Source("G") };
|
||||
var safe = new List<string>();
|
||||
ForEachWrap(safe, SinkMethodGroup2);
|
||||
ForEachWrap(tainted, SinkMethodGroup1);
|
||||
}
|
||||
|
||||
class TaintedClass
|
||||
{
|
||||
public override string ToString() => Source("TaintedClass");
|
||||
}
|
||||
|
||||
class SafeClass
|
||||
{
|
||||
public override string ToString() => "safe";
|
||||
}
|
||||
|
||||
string ConvertToString(object o) => o.ToString();
|
||||
|
||||
string ConvertToStringWrap(object o) => ConvertToString(o);
|
||||
|
||||
void TestToString1()
|
||||
{
|
||||
var unused = ConvertToStringWrap(new TaintedClass());
|
||||
Sink(ConvertToStringWrap(new SafeClass())); // no flow
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
testFailures
|
||||
edges
|
||||
| TypeFlowDispatch.cs:11:42:11:42 | x : String | TypeFlowDispatch.cs:13:11:13:11 | access to parameter x : String |
|
||||
| TypeFlowDispatch.cs:11:42:11:42 | x : String | TypeFlowDispatch.cs:13:11:13:11 | access to parameter x : String |
|
||||
| TypeFlowDispatch.cs:13:11:13:11 | access to parameter x : String | TypeFlowDispatch.cs:23:20:23:20 | x : String |
|
||||
| TypeFlowDispatch.cs:13:11:13:11 | access to parameter x : String | TypeFlowDispatch.cs:23:20:23:20 | x : String |
|
||||
| TypeFlowDispatch.cs:16:46:16:46 | x : String | TypeFlowDispatch.cs:18:19:18:19 | access to parameter x : String |
|
||||
| TypeFlowDispatch.cs:16:46:16:46 | x : String | TypeFlowDispatch.cs:18:19:18:19 | access to parameter x : String |
|
||||
| TypeFlowDispatch.cs:18:19:18:19 | access to parameter x : String | TypeFlowDispatch.cs:11:42:11:42 | x : String |
|
||||
| TypeFlowDispatch.cs:18:19:18:19 | access to parameter x : String | TypeFlowDispatch.cs:11:42:11:42 | x : String |
|
||||
| TypeFlowDispatch.cs:23:20:23:20 | x : String | TypeFlowDispatch.cs:23:32:23:32 | access to parameter x |
|
||||
| TypeFlowDispatch.cs:23:20:23:20 | x : String | TypeFlowDispatch.cs:23:32:23:32 | access to parameter x |
|
||||
| TypeFlowDispatch.cs:23:39:23:49 | call to method Source<String> : String | TypeFlowDispatch.cs:16:46:16:46 | x : String |
|
||||
| TypeFlowDispatch.cs:23:39:23:49 | call to method Source<String> : String | TypeFlowDispatch.cs:16:46:16:46 | x : String |
|
||||
| TypeFlowDispatch.cs:29:37:29:37 | l : List<T> [element] : String | TypeFlowDispatch.cs:31:9:31:9 | access to parameter l : List<T> [element] : String |
|
||||
| TypeFlowDispatch.cs:29:37:29:37 | l : List<T> [element] : String | TypeFlowDispatch.cs:31:9:31:9 | access to parameter l : List<T> [element] : String |
|
||||
| TypeFlowDispatch.cs:31:9:31:9 | access to parameter l : List<T> [element] : String | TypeFlowDispatch.cs:39:34:39:34 | x : String |
|
||||
| TypeFlowDispatch.cs:31:9:31:9 | access to parameter l : List<T> [element] : String | TypeFlowDispatch.cs:39:34:39:34 | x : String |
|
||||
| TypeFlowDispatch.cs:36:23:36:54 | object creation of type List<String> : List<T> [element] : String | TypeFlowDispatch.cs:39:25:39:31 | access to local variable tainted : List<T> [element] : String |
|
||||
| TypeFlowDispatch.cs:36:23:36:54 | object creation of type List<String> : List<T> [element] : String | TypeFlowDispatch.cs:39:25:39:31 | access to local variable tainted : List<T> [element] : String |
|
||||
| TypeFlowDispatch.cs:36:42:36:52 | call to method Source<String> : String | TypeFlowDispatch.cs:36:23:36:54 | object creation of type List<String> : List<T> [element] : String |
|
||||
| TypeFlowDispatch.cs:36:42:36:52 | call to method Source<String> : String | TypeFlowDispatch.cs:36:23:36:54 | object creation of type List<String> : List<T> [element] : String |
|
||||
| TypeFlowDispatch.cs:39:25:39:31 | access to local variable tainted : List<T> [element] : String | TypeFlowDispatch.cs:29:37:29:37 | l : List<T> [element] : String |
|
||||
| TypeFlowDispatch.cs:39:25:39:31 | access to local variable tainted : List<T> [element] : String | TypeFlowDispatch.cs:29:37:29:37 | l : List<T> [element] : String |
|
||||
| TypeFlowDispatch.cs:39:34:39:34 | x : String | TypeFlowDispatch.cs:39:46:39:46 | access to parameter x |
|
||||
| TypeFlowDispatch.cs:39:34:39:34 | x : String | TypeFlowDispatch.cs:39:46:39:46 | access to parameter x |
|
||||
| TypeFlowDispatch.cs:42:42:42:42 | x : String | TypeFlowDispatch.cs:44:11:44:11 | access to parameter x : String |
|
||||
| TypeFlowDispatch.cs:42:42:42:42 | x : String | TypeFlowDispatch.cs:44:11:44:11 | access to parameter x : String |
|
||||
| TypeFlowDispatch.cs:44:11:44:11 | access to parameter x : String | TypeFlowDispatch.cs:52:32:52:32 | t : String |
|
||||
| TypeFlowDispatch.cs:44:11:44:11 | access to parameter x : String | TypeFlowDispatch.cs:52:32:52:32 | t : String |
|
||||
| TypeFlowDispatch.cs:47:46:47:46 | x : String | TypeFlowDispatch.cs:49:19:49:19 | access to parameter x : String |
|
||||
| TypeFlowDispatch.cs:47:46:47:46 | x : String | TypeFlowDispatch.cs:49:19:49:19 | access to parameter x : String |
|
||||
| TypeFlowDispatch.cs:49:19:49:19 | access to parameter x : String | TypeFlowDispatch.cs:42:42:42:42 | x : String |
|
||||
| TypeFlowDispatch.cs:49:19:49:19 | access to parameter x : String | TypeFlowDispatch.cs:42:42:42:42 | x : String |
|
||||
| TypeFlowDispatch.cs:52:32:52:32 | t : String | TypeFlowDispatch.cs:52:43:52:43 | access to parameter t |
|
||||
| TypeFlowDispatch.cs:52:32:52:32 | t : String | TypeFlowDispatch.cs:52:43:52:43 | access to parameter t |
|
||||
| TypeFlowDispatch.cs:57:38:57:48 | call to method Source<String> : String | TypeFlowDispatch.cs:47:46:47:46 | x : String |
|
||||
| TypeFlowDispatch.cs:57:38:57:48 | call to method Source<String> : String | TypeFlowDispatch.cs:47:46:47:46 | x : String |
|
||||
| TypeFlowDispatch.cs:61:29:61:29 | l : List<T> [element] : String | TypeFlowDispatch.cs:63:27:63:27 | access to parameter l : List<T> [element] : String |
|
||||
| TypeFlowDispatch.cs:61:29:61:29 | l : List<T> [element] : String | TypeFlowDispatch.cs:63:27:63:27 | access to parameter l : List<T> [element] : String |
|
||||
| TypeFlowDispatch.cs:63:22:63:22 | SSA def(x) : String | TypeFlowDispatch.cs:64:15:64:15 | access to local variable x : String |
|
||||
| TypeFlowDispatch.cs:63:22:63:22 | SSA def(x) : String | TypeFlowDispatch.cs:64:15:64:15 | access to local variable x : String |
|
||||
| TypeFlowDispatch.cs:63:27:63:27 | access to parameter l : List<T> [element] : String | TypeFlowDispatch.cs:63:22:63:22 | SSA def(x) : String |
|
||||
| TypeFlowDispatch.cs:63:27:63:27 | access to parameter l : List<T> [element] : String | TypeFlowDispatch.cs:63:22:63:22 | SSA def(x) : String |
|
||||
| TypeFlowDispatch.cs:64:15:64:15 | access to local variable x : String | TypeFlowDispatch.cs:52:32:52:32 | t : String |
|
||||
| TypeFlowDispatch.cs:64:15:64:15 | access to local variable x : String | TypeFlowDispatch.cs:52:32:52:32 | t : String |
|
||||
| TypeFlowDispatch.cs:67:33:67:33 | l : List<T> [element] : String | TypeFlowDispatch.cs:69:17:69:17 | access to parameter l : List<T> [element] : String |
|
||||
| TypeFlowDispatch.cs:67:33:67:33 | l : List<T> [element] : String | TypeFlowDispatch.cs:69:17:69:17 | access to parameter l : List<T> [element] : String |
|
||||
| TypeFlowDispatch.cs:69:17:69:17 | access to parameter l : List<T> [element] : String | TypeFlowDispatch.cs:61:29:61:29 | l : List<T> [element] : String |
|
||||
| TypeFlowDispatch.cs:69:17:69:17 | access to parameter l : List<T> [element] : String | TypeFlowDispatch.cs:61:29:61:29 | l : List<T> [element] : String |
|
||||
| TypeFlowDispatch.cs:74:23:74:54 | object creation of type List<String> : List<T> [element] : String | TypeFlowDispatch.cs:77:21:77:27 | access to local variable tainted : List<T> [element] : String |
|
||||
| TypeFlowDispatch.cs:74:23:74:54 | object creation of type List<String> : List<T> [element] : String | TypeFlowDispatch.cs:77:21:77:27 | access to local variable tainted : List<T> [element] : String |
|
||||
| TypeFlowDispatch.cs:74:42:74:52 | call to method Source<String> : String | TypeFlowDispatch.cs:74:23:74:54 | object creation of type List<String> : List<T> [element] : String |
|
||||
| TypeFlowDispatch.cs:74:42:74:52 | call to method Source<String> : String | TypeFlowDispatch.cs:74:23:74:54 | object creation of type List<String> : List<T> [element] : String |
|
||||
| TypeFlowDispatch.cs:77:21:77:27 | access to local variable tainted : List<T> [element] : String | TypeFlowDispatch.cs:67:33:67:33 | l : List<T> [element] : String |
|
||||
| TypeFlowDispatch.cs:77:21:77:27 | access to local variable tainted : List<T> [element] : String | TypeFlowDispatch.cs:67:33:67:33 | l : List<T> [element] : String |
|
||||
nodes
|
||||
| TypeFlowDispatch.cs:11:42:11:42 | x : String | semmle.label | x : String |
|
||||
| TypeFlowDispatch.cs:11:42:11:42 | x : String | semmle.label | x : String |
|
||||
| TypeFlowDispatch.cs:13:11:13:11 | access to parameter x : String | semmle.label | access to parameter x : String |
|
||||
| TypeFlowDispatch.cs:13:11:13:11 | access to parameter x : String | semmle.label | access to parameter x : String |
|
||||
| TypeFlowDispatch.cs:16:46:16:46 | x : String | semmle.label | x : String |
|
||||
| TypeFlowDispatch.cs:16:46:16:46 | x : String | semmle.label | x : String |
|
||||
| TypeFlowDispatch.cs:18:19:18:19 | access to parameter x : String | semmle.label | access to parameter x : String |
|
||||
| TypeFlowDispatch.cs:18:19:18:19 | access to parameter x : String | semmle.label | access to parameter x : String |
|
||||
| TypeFlowDispatch.cs:23:20:23:20 | x : String | semmle.label | x : String |
|
||||
| TypeFlowDispatch.cs:23:20:23:20 | x : String | semmle.label | x : String |
|
||||
| TypeFlowDispatch.cs:23:32:23:32 | access to parameter x | semmle.label | access to parameter x |
|
||||
| TypeFlowDispatch.cs:23:32:23:32 | access to parameter x | semmle.label | access to parameter x |
|
||||
| TypeFlowDispatch.cs:23:39:23:49 | call to method Source<String> : String | semmle.label | call to method Source<String> : String |
|
||||
| TypeFlowDispatch.cs:23:39:23:49 | call to method Source<String> : String | semmle.label | call to method Source<String> : String |
|
||||
| TypeFlowDispatch.cs:29:37:29:37 | l : List<T> [element] : String | semmle.label | l : List<T> [element] : String |
|
||||
| TypeFlowDispatch.cs:29:37:29:37 | l : List<T> [element] : String | semmle.label | l : List<T> [element] : String |
|
||||
| TypeFlowDispatch.cs:31:9:31:9 | access to parameter l : List<T> [element] : String | semmle.label | access to parameter l : List<T> [element] : String |
|
||||
| TypeFlowDispatch.cs:31:9:31:9 | access to parameter l : List<T> [element] : String | semmle.label | access to parameter l : List<T> [element] : String |
|
||||
| TypeFlowDispatch.cs:36:23:36:54 | object creation of type List<String> : List<T> [element] : String | semmle.label | object creation of type List<String> : List<T> [element] : String |
|
||||
| TypeFlowDispatch.cs:36:23:36:54 | object creation of type List<String> : List<T> [element] : String | semmle.label | object creation of type List<String> : List<T> [element] : String |
|
||||
| TypeFlowDispatch.cs:36:42:36:52 | call to method Source<String> : String | semmle.label | call to method Source<String> : String |
|
||||
| TypeFlowDispatch.cs:36:42:36:52 | call to method Source<String> : String | semmle.label | call to method Source<String> : String |
|
||||
| TypeFlowDispatch.cs:39:25:39:31 | access to local variable tainted : List<T> [element] : String | semmle.label | access to local variable tainted : List<T> [element] : String |
|
||||
| TypeFlowDispatch.cs:39:25:39:31 | access to local variable tainted : List<T> [element] : String | semmle.label | access to local variable tainted : List<T> [element] : String |
|
||||
| TypeFlowDispatch.cs:39:34:39:34 | x : String | semmle.label | x : String |
|
||||
| TypeFlowDispatch.cs:39:34:39:34 | x : String | semmle.label | x : String |
|
||||
| TypeFlowDispatch.cs:39:46:39:46 | access to parameter x | semmle.label | access to parameter x |
|
||||
| TypeFlowDispatch.cs:39:46:39:46 | access to parameter x | semmle.label | access to parameter x |
|
||||
| TypeFlowDispatch.cs:42:42:42:42 | x : String | semmle.label | x : String |
|
||||
| TypeFlowDispatch.cs:42:42:42:42 | x : String | semmle.label | x : String |
|
||||
| TypeFlowDispatch.cs:44:11:44:11 | access to parameter x : String | semmle.label | access to parameter x : String |
|
||||
| TypeFlowDispatch.cs:44:11:44:11 | access to parameter x : String | semmle.label | access to parameter x : String |
|
||||
| TypeFlowDispatch.cs:47:46:47:46 | x : String | semmle.label | x : String |
|
||||
| TypeFlowDispatch.cs:47:46:47:46 | x : String | semmle.label | x : String |
|
||||
| TypeFlowDispatch.cs:49:19:49:19 | access to parameter x : String | semmle.label | access to parameter x : String |
|
||||
| TypeFlowDispatch.cs:49:19:49:19 | access to parameter x : String | semmle.label | access to parameter x : String |
|
||||
| TypeFlowDispatch.cs:52:32:52:32 | t : String | semmle.label | t : String |
|
||||
| TypeFlowDispatch.cs:52:32:52:32 | t : String | semmle.label | t : String |
|
||||
| TypeFlowDispatch.cs:52:43:52:43 | access to parameter t | semmle.label | access to parameter t |
|
||||
| TypeFlowDispatch.cs:52:43:52:43 | access to parameter t | semmle.label | access to parameter t |
|
||||
| TypeFlowDispatch.cs:57:38:57:48 | call to method Source<String> : String | semmle.label | call to method Source<String> : String |
|
||||
| TypeFlowDispatch.cs:57:38:57:48 | call to method Source<String> : String | semmle.label | call to method Source<String> : String |
|
||||
| TypeFlowDispatch.cs:61:29:61:29 | l : List<T> [element] : String | semmle.label | l : List<T> [element] : String |
|
||||
| TypeFlowDispatch.cs:61:29:61:29 | l : List<T> [element] : String | semmle.label | l : List<T> [element] : String |
|
||||
| TypeFlowDispatch.cs:63:22:63:22 | SSA def(x) : String | semmle.label | SSA def(x) : String |
|
||||
| TypeFlowDispatch.cs:63:22:63:22 | SSA def(x) : String | semmle.label | SSA def(x) : String |
|
||||
| TypeFlowDispatch.cs:63:27:63:27 | access to parameter l : List<T> [element] : String | semmle.label | access to parameter l : List<T> [element] : String |
|
||||
| TypeFlowDispatch.cs:63:27:63:27 | access to parameter l : List<T> [element] : String | semmle.label | access to parameter l : List<T> [element] : String |
|
||||
| TypeFlowDispatch.cs:64:15:64:15 | access to local variable x : String | semmle.label | access to local variable x : String |
|
||||
| TypeFlowDispatch.cs:64:15:64:15 | access to local variable x : String | semmle.label | access to local variable x : String |
|
||||
| TypeFlowDispatch.cs:67:33:67:33 | l : List<T> [element] : String | semmle.label | l : List<T> [element] : String |
|
||||
| TypeFlowDispatch.cs:67:33:67:33 | l : List<T> [element] : String | semmle.label | l : List<T> [element] : String |
|
||||
| TypeFlowDispatch.cs:69:17:69:17 | access to parameter l : List<T> [element] : String | semmle.label | access to parameter l : List<T> [element] : String |
|
||||
| TypeFlowDispatch.cs:69:17:69:17 | access to parameter l : List<T> [element] : String | semmle.label | access to parameter l : List<T> [element] : String |
|
||||
| TypeFlowDispatch.cs:74:23:74:54 | object creation of type List<String> : List<T> [element] : String | semmle.label | object creation of type List<String> : List<T> [element] : String |
|
||||
| TypeFlowDispatch.cs:74:23:74:54 | object creation of type List<String> : List<T> [element] : String | semmle.label | object creation of type List<String> : List<T> [element] : String |
|
||||
| TypeFlowDispatch.cs:74:42:74:52 | call to method Source<String> : String | semmle.label | call to method Source<String> : String |
|
||||
| TypeFlowDispatch.cs:74:42:74:52 | call to method Source<String> : String | semmle.label | call to method Source<String> : String |
|
||||
| TypeFlowDispatch.cs:77:21:77:27 | access to local variable tainted : List<T> [element] : String | semmle.label | access to local variable tainted : List<T> [element] : String |
|
||||
| TypeFlowDispatch.cs:77:21:77:27 | access to local variable tainted : List<T> [element] : String | semmle.label | access to local variable tainted : List<T> [element] : String |
|
||||
subpaths
|
||||
#select
|
||||
| TypeFlowDispatch.cs:23:32:23:32 | access to parameter x | TypeFlowDispatch.cs:23:39:23:49 | call to method Source<String> : String | TypeFlowDispatch.cs:23:32:23:32 | access to parameter x | $@ | TypeFlowDispatch.cs:23:39:23:49 | call to method Source<String> : String | call to method Source<String> : String |
|
||||
| TypeFlowDispatch.cs:23:32:23:32 | access to parameter x | TypeFlowDispatch.cs:23:39:23:49 | call to method Source<String> : String | TypeFlowDispatch.cs:23:32:23:32 | access to parameter x | $@ | TypeFlowDispatch.cs:23:39:23:49 | call to method Source<String> : String | call to method Source<String> : String |
|
||||
| TypeFlowDispatch.cs:39:46:39:46 | access to parameter x | TypeFlowDispatch.cs:36:42:36:52 | call to method Source<String> : String | TypeFlowDispatch.cs:39:46:39:46 | access to parameter x | $@ | TypeFlowDispatch.cs:36:42:36:52 | call to method Source<String> : String | call to method Source<String> : String |
|
||||
| TypeFlowDispatch.cs:39:46:39:46 | access to parameter x | TypeFlowDispatch.cs:36:42:36:52 | call to method Source<String> : String | TypeFlowDispatch.cs:39:46:39:46 | access to parameter x | $@ | TypeFlowDispatch.cs:36:42:36:52 | call to method Source<String> : String | call to method Source<String> : String |
|
||||
| TypeFlowDispatch.cs:52:43:52:43 | access to parameter t | TypeFlowDispatch.cs:57:38:57:48 | call to method Source<String> : String | TypeFlowDispatch.cs:52:43:52:43 | access to parameter t | $@ | TypeFlowDispatch.cs:57:38:57:48 | call to method Source<String> : String | call to method Source<String> : String |
|
||||
| TypeFlowDispatch.cs:52:43:52:43 | access to parameter t | TypeFlowDispatch.cs:57:38:57:48 | call to method Source<String> : String | TypeFlowDispatch.cs:52:43:52:43 | access to parameter t | $@ | TypeFlowDispatch.cs:57:38:57:48 | call to method Source<String> : String | call to method Source<String> : String |
|
||||
| TypeFlowDispatch.cs:52:43:52:43 | access to parameter t | TypeFlowDispatch.cs:74:42:74:52 | call to method Source<String> : String | TypeFlowDispatch.cs:52:43:52:43 | access to parameter t | $@ | TypeFlowDispatch.cs:74:42:74:52 | call to method Source<String> : String | call to method Source<String> : String |
|
||||
| TypeFlowDispatch.cs:52:43:52:43 | access to parameter t | TypeFlowDispatch.cs:74:42:74:52 | call to method Source<String> : String | TypeFlowDispatch.cs:52:43:52:43 | access to parameter t | $@ | TypeFlowDispatch.cs:74:42:74:52 | call to method Source<String> : String | call to method Source<String> : String |
|
||||
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* @kind path-problem
|
||||
*/
|
||||
|
||||
import csharp
|
||||
import TestUtilities.InlineFlowTest
|
||||
import DefaultFlowTest
|
||||
import PathGraph
|
||||
|
||||
from PathNode source, PathNode sink
|
||||
where flowPath(source, sink)
|
||||
select sink, source, sink, "$@", source, source.toString()
|
||||
@@ -0,0 +1,2 @@
|
||||
semmle-extractor-options: /nostdlib /noconfig
|
||||
semmle-extractor-options: --load-sources-from-project:${testdir}/../../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj
|
||||
Reference in New Issue
Block a user