diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/CallContext.qll b/csharp/ql/src/semmle/code/csharp/dataflow/CallContext.qll index c36bcc0dc8a..b0a6d9d98ed 100755 --- a/csharp/ql/src/semmle/code/csharp/dataflow/CallContext.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/CallContext.qll @@ -11,10 +11,7 @@ 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)) } or - TDelegateToLibraryCallableArgCallContext(DelegateArgumentToLibraryCallable arg, int i) { - exists(arg.getDelegateType().getParameter(i)) - } + TArgDelegateCallContext(DelegateCall dc, int i) { exists(dc.getArgument(i)) } /** * A call context. @@ -79,31 +76,3 @@ class DelegateCallArgumentCallContext extends ArgumentCallContext, TArgDelegateC override Location getLocation() { result = dc.getArgument(arg).getLocation() } } - -/** - * An argument of a call to a delegate supplied to a library callable, - * identified by the delegate argument itself. - * - * For example, in `x.Select(y => y)` the call to the supplied delegate - * that happens inside the library callable `Select` is not available - * in the database, so the delegate argument `y => y` is used to - * represent the call. - */ -class DelegateArgumentToLibraryCallableArgumentContext extends ArgumentCallContext, - TDelegateToLibraryCallableArgCallContext { - Expr delegate; - int arg; - - DelegateArgumentToLibraryCallableArgumentContext() { - this = TDelegateToLibraryCallableArgCallContext(delegate, arg) - } - - override predicate isArgument(Expr call, int i) { - call = delegate and - i = arg - } - - override string toString() { result = "argument " + arg + " of " + delegate.toString() } - - override Location getLocation() { result = delegate.getLocation() } -} diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/LibraryTypeDataFlow.qll b/csharp/ql/src/semmle/code/csharp/dataflow/LibraryTypeDataFlow.qll index ebd9324f8f8..c1c10b9bf49 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/LibraryTypeDataFlow.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/LibraryTypeDataFlow.qll @@ -199,27 +199,13 @@ class CallableFlowSink extends TCallableFlowSink { /** Gets the sink of flow for call `c`, if any. */ Expr getSink(Call c) { none() } - - /** - * Gets the type of the sink for call `c`. Unlike `getSink()`, this is defined - * for all flow sink specifications. - */ - Type getSinkType(Call c) { result = this.getSink(c).getType() } } /** A flow sink specification: (method call) qualifier. */ class CallableFlowSinkQualifier extends CallableFlowSink, TCallableFlowSinkQualifier { override string toString() { result = "qualifier" } - override Expr getSink(Call c) { - result = c.getChild(-1) - or - // E.g. `new Dictionary{ {0, "a"}, {1, "b"} }` - result.(CollectionInitializer).getAnElementInitializer() = c - or - // E.g. `new Dictionary() { [0] = "a", [1] = "b" }` - result.(ObjectInitializer).getAMemberInitializer().getLValue() = c - } + override Expr getSink(Call c) { result = c.getChild(-1) } } /** A flow sink specification: return value. */ @@ -253,8 +239,6 @@ class CallableFlowSinkArg extends CallableFlowSink, TCallableFlowSinkArg { // The uses of the `i`th argument are the actual sinks none() } - - override Type getSinkType(Call c) { result = this.getArgument(c).getType() } } private predicate isCollectionType(ValueOrRefType t) { @@ -312,16 +296,6 @@ class CallableFlowSinkDelegateArg extends CallableFlowSink, TCallableFlowSinkDel // The uses of the `j`th parameter are the actual sinks none() } - - override Type getSinkType(Call c) { - result = - c - .getArgument(delegateIndex) - .(DelegateArgumentToLibraryCallable) - .getDelegateType() - .getParameter(parameterIndex) - .getType() - } } /** A specification of data flow for a library (non-source code) type. */ diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/SSA.qll b/csharp/ql/src/semmle/code/csharp/dataflow/SSA.qll index 75b03ac52df..928682a761e 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/SSA.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/SSA.qll @@ -1018,7 +1018,7 @@ module Ssa { private predicate intraInstanceCallEdge(Callable c1, InstanceCallable c2) { exists(Call c | c.getEnclosingCallable() = c1 and - c2 = getARuntimeTarget(c) and + c2 = getARuntimeTarget(c, _) and c.(QualifiableExpr).targetIsLocalInstance() ) } @@ -1034,15 +1034,28 @@ module Ssa { * the SSA library and `Call.getARuntimeTarget()` mutually recursive), and * * (3) indirect calls to delegates via calls to library callables are included. + * + * The Boolean `libraryDelegateCall` indicates whether `c` is a call to a library + * method and the result is a delegate passed to `c`. For example, in + * + * ```csharp + * Lazy M1() + * { + * return new Lazy(M2); + * } + * ``` + * + * the constructor call `new Lazy(M2)` includes `M2` as a target. */ - Callable getARuntimeTarget(Call c) { + Callable getARuntimeTarget(Call c, boolean libraryDelegateCall) { // Non-delegate call: use dispatch library exists(DispatchCall dc | dc.getCall() = c | - result = dc.getADynamicTarget().getSourceDeclaration() + result = dc.getADynamicTarget().getSourceDeclaration() and + libraryDelegateCall = false ) or // Delegate call: use simple analysis - result = SimpleDelegateAnalysis::getARuntimeDelegateTarget(c) + result = SimpleDelegateAnalysis::getARuntimeDelegateTarget(c, libraryDelegateCall) } private module SimpleDelegateAnalysis { @@ -1055,12 +1068,14 @@ module Ssa { * Either `c` is a delegate call and `e` is the qualifier, or `c` is a call to * a library callable and `e` is a delegate argument. */ - private predicate delegateCall(Call c, Expr e) { - c = any(DelegateCall dc | e = dc.getDelegateExpr()) + private predicate delegateCall(Call c, Expr e, boolean libraryDelegateCall) { + c = any(DelegateCall dc | e = dc.getDelegateExpr()) and + libraryDelegateCall = false or c.getTarget().fromLibrary() and e = c.getAnArgument() and - e.getType() instanceof SystemLinqExpressions::DelegateExtType + e.getType() instanceof SystemLinqExpressions::DelegateExtType and + libraryDelegateCall = true } /** Holds if expression `e` is a delegate creation for callable `c` of type `t`. */ @@ -1090,7 +1105,7 @@ module Ssa { callable = call.getTarget() or callable = call.getTarget().(Method).getAnOverrider+() or callable = call.getTarget().(Method).getAnUltimateImplementor() or - callable = getARuntimeDelegateTarget(call) + callable = getARuntimeDelegateTarget(call, false) ) or pred = succ.(DelegateCreation).getArgument() @@ -1110,7 +1125,7 @@ module Ssa { } private predicate reachesDelegateCall(Expr e) { - delegateCall(_, e) + delegateCall(_, e, _) or exists(Expr mid | reachesDelegateCall(mid) | delegateFlowStep(e, mid)) } @@ -1128,12 +1143,14 @@ module Ssa { } /** Gets a run-time target for the delegate call `c`. */ - Callable getARuntimeDelegateTarget(Call c) { delegateCall(c, delegateCallSource(result)) } + Callable getARuntimeDelegateTarget(Call c, boolean libraryDelegateCall) { + delegateCall(c, delegateCallSource(result), libraryDelegateCall) + } } /** Holds if `(c1,c2)` is an edge in the call graph. */ predicate callEdge(Callable c1, Callable c2) { - exists(Call c | c.getEnclosingCallable() = c1 | getARuntimeTarget(c) = c2) + exists(Call c | c.getEnclosingCallable() = c1 and c2 = getARuntimeTarget(c, _)) } /** @@ -1179,7 +1196,7 @@ module Ssa { pragma[noinline] predicate callAt(BasicBlock bb, int i, Call call) { bb.getNode(i) = call.getAControlFlowNode() and - getARuntimeTarget(call).hasBody() + getARuntimeTarget(call, _).hasBody() } /** @@ -1201,7 +1218,7 @@ module Ssa { private predicate pruneFromLeft(Callable c) { exists(Call call, TrackedFieldOrProp f | updateCandidate(_, _, f, call) and - c = getARuntimeTarget(call) and + c = getARuntimeTarget(call, _) and generalSetter(_, f.getAssignable(), _) ) or @@ -1238,7 +1255,7 @@ module Ssa { updateCandidate(_, _, tfp, call) and fp = tfp.getAssignable() and generalSetter(_, fp, _) and - c1 = getARuntimeTarget(call) + c1 = getARuntimeTarget(call, _) } pragma[noinline] @@ -1279,7 +1296,7 @@ module Ssa { Call call, TrackedFieldOrProp tfp, Callable setter ) { updateCandidate(_, _, tfp, call) and - setsOwnFieldOrPropTransitive(getARuntimeTarget(call), tfp.getAssignable(), setter) + setsOwnFieldOrPropTransitive(getARuntimeTarget(call, _), tfp.getAssignable(), setter) } private predicate updatesNamedFieldOrPropPossiblyLive( @@ -1447,7 +1464,7 @@ module Ssa { private predicate pruneFromLeft(Callable c) { exists(Call call, CapturedWrittenLocalScopeSourceVariable v | updateCandidate(_, _, v, call) and - c = getARuntimeTarget(call) and + c = getARuntimeTarget(call, _) and relevantDefinition(_, v.getAssignable(), _) ) or @@ -1485,12 +1502,12 @@ module Ssa { pragma[noinline] private predicate updatesCapturedVariablePrefix( Call call, CapturedWrittenLocalScopeSourceVariable v, PrunedCallable c, - CapturedWrittenLocalScopeVariable captured + CapturedWrittenLocalScopeVariable captured, boolean libraryDelegateCall ) { updateCandidate(_, _, v, call) and captured = v.getAssignable() and relevantDefinitionProj(_, captured) and - c = getARuntimeTarget(call) + c = getARuntimeTarget(call, libraryDelegateCall) } /** @@ -1505,11 +1522,13 @@ module Ssa { Call call, CapturedWrittenLocalScopeSourceVariable v, PrunedCallable writer, boolean additionalCalls ) { - exists(PrunedCallable c, CapturedWrittenLocalScopeVariable captured | - updatesCapturedVariablePrefix(call, v, c, captured) and + exists( + PrunedCallable c, CapturedWrittenLocalScopeVariable captured, boolean libraryDelegateCall + | + updatesCapturedVariablePrefix(call, v, c, captured, libraryDelegateCall) and relevantDefinitionProj(writer, captured) and ( - c = writer and additionalCalls = false + c = writer and additionalCalls = libraryDelegateCall or callEdgePrunedPlus(c, writer) and additionalCalls = true ) @@ -1667,7 +1686,7 @@ module Ssa { private predicate pruneFromLeft(Callable c) { exists(Call call, CapturedReadLocalScopeSourceVariable v | implicitReadCandidate(_, _, call.getAControlFlowNode(), v) and - c = getARuntimeTarget(call) + c = getARuntimeTarget(call, _) ) or exists(Callable mid | pruneFromLeft(mid) | callEdge(mid, c)) @@ -1702,12 +1721,12 @@ module Ssa { pragma[noinline] private predicate readsCapturedVariablePrefix( ControlFlow::Node call, CapturedReadLocalScopeSourceVariable v, PrunedCallable c, - CapturedReadLocalScopeVariable captured + CapturedReadLocalScopeVariable captured, boolean libraryDelegateCall ) { implicitReadCandidate(_, _, call, v) and captured = v.getAssignable() and capturerReads(_, captured) and - c = getARuntimeTarget(call.getElement()) + c = getARuntimeTarget(call.getElement(), libraryDelegateCall) } /** @@ -1722,11 +1741,13 @@ module Ssa { ControlFlow::Nodes::ElementNode call, CapturedReadLocalScopeSourceVariable v, Callable reader, boolean additionalCalls ) { - exists(PrunedCallable c, CapturedReadLocalScopeVariable captured | - readsCapturedVariablePrefix(call, v, c, captured) and + exists( + PrunedCallable c, CapturedReadLocalScopeVariable captured, boolean libraryDelegateCall + | + readsCapturedVariablePrefix(call, v, c, captured, libraryDelegateCall) and capturerReads(reader, captured) and ( - c = reader and additionalCalls = false + c = reader and additionalCalls = libraryDelegateCall or callEdgePrunedPlus(c, reader) and additionalCalls = true ) @@ -1765,7 +1786,6 @@ module Ssa { def.getSourceVariable().getAssignable() = lsv | lsv = v.getAssignable() and - adef = def.getAPossibleDefinition() and bb.getNode(i) = adef.getAControlFlowNode() and updatesCapturedVariable(def.getCall(), _, adef, additionalCalls) ) diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll index 25ca28ea789..08d099961d0 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll @@ -3,18 +3,24 @@ private import cil private import dotnet private import DataFlowPrivate private import DelegateDataFlow +private import semmle.code.csharp.dataflow.LibraryTypeDataFlow private import semmle.code.csharp.dispatch.Dispatch private import semmle.code.csharp.frameworks.system.Collections private import semmle.code.csharp.frameworks.system.collections.Generic /** - * Gets a source declaration of callable `c` that has a body. + * Gets a source declaration of callable `c` that has a body or has + * a flow summary. + * * If the callable has both CIL and source code, return only the source * code version. */ DotNet::Callable getCallableForDataFlow(DotNet::Callable c) { - result.hasBody() and exists(DotNet::Callable sourceDecl | sourceDecl = c.getSourceDeclaration() | + result = sourceDecl and + Summaries::summary(result, _, _, _, _, _) + or + result.hasBody() and if sourceDecl.getFile().fromSource() then // C# callable with C# implementation in the database @@ -83,7 +89,8 @@ private module Cached { exists(Ssa::ExplicitDefinition def | def.isCapturedVariableDefinitionFlowOut(_, _) | v = def.getSourceVariable().getAssignable() ) - } + } or + TQualifierReturnKind() cached newtype TDataFlowCall = @@ -93,15 +100,23 @@ private module Cached { TExplicitDelegateCall(ControlFlow::Nodes::ElementNode cfn, DelegateCall dc) { cfn.getElement() = dc } or - TImplicitDelegateCall(ControlFlow::Nodes::ElementNode cfn, DelegateArgumentToLibraryCallable arg) { - cfn.getElement() = arg - } or TTransitiveCapturedCall(ControlFlow::Nodes::ElementNode cfn, Callable target) { transitiveCapturedCallTarget(cfn, target) } or TCilCall(CIL::Call call) { // No need to include calls that are compiled from source not call.getImplementation().getMethod().compiledFromSource() + } or + TSummaryDelegateCall(SourceDeclarationCallable c, int pos) { + exists(CallableFlowSourceDelegateArg source | + Summaries::summary(c, source, _, _, _, _) and + pos = source.getArgumentIndex() + ) + or + exists(CallableFlowSinkDelegateArg sink | + Summaries::summary(c, _, _, sink, _, _) and + pos = sink.getDelegateIndex() + ) } /** Gets a viable run-time target for the call `call`. */ @@ -118,7 +133,7 @@ private module DispatchImpl { * Gets a viable run-time target for the delegate call `call`, requiring * call context `cc`. */ - private DotNet::Callable viableDelegateCallable(DataFlowCall call, CallContext cc) { + private DataFlowCallable viableDelegateCallable(DataFlowCall call, CallContext cc) { result = call.(DelegateDataFlowCall).getARuntimeTarget(cc) } @@ -143,7 +158,7 @@ private module DispatchImpl { * 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. */ - DotNet::Callable viableImplInCallContext(DataFlowCall call, DataFlowCall ctx) { + DataFlowCallable viableImplInCallContext(DataFlowCall call, DataFlowCall ctx) { exists(ArgumentCallContext cc | result = viableDelegateCallable(call, cc) | cc.isArgument(ctx.getExpr(), _) ) @@ -153,6 +168,7 @@ private module DispatchImpl { .(NonDelegateDataFlowCall) .getDispatchCall() .getADynamicTargetInCallContext(ctx.(NonDelegateDataFlowCall).getDispatchCall()) + .getSourceDeclaration() } } @@ -218,6 +234,11 @@ class ImplicitCapturedReturnKind extends ReturnKind, TImplicitCapturedReturnKind override string toString() { result = "captured " + v } } +/** A value returned through the qualifier of a call. */ +class QualifierReturnKind extends ReturnKind, TQualifierReturnKind { + override string toString() { result = "qualifier" } +} + class DataFlowCallable = DotNet::Callable; /** A call relevant for data flow. */ @@ -261,7 +282,7 @@ class NonDelegateDataFlowCall extends DataFlowCall, TNonDelegateCall { /** Gets the underlying call. */ DispatchCall getDispatchCall() { result = dc } - override DotNet::Callable getARuntimeTarget() { + override DataFlowCallable getARuntimeTarget() { result = getCallableForDataFlow(dc.getADynamicTarget()) } @@ -279,9 +300,9 @@ 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 DotNet::Callable getARuntimeTarget(CallContext::CallContext cc); + abstract DataFlowCallable getARuntimeTarget(CallContext::CallContext cc); - override DotNet::Callable getARuntimeTarget() { result = this.getARuntimeTarget(_) } + override DataFlowCallable getARuntimeTarget() { result = this.getARuntimeTarget(_) } } /** An explicit delegate call relevant for data flow. */ @@ -291,8 +312,8 @@ class ExplicitDelegateDataFlowCall extends DelegateDataFlowCall, TExplicitDelega ExplicitDelegateDataFlowCall() { this = TExplicitDelegateCall(cfn, dc) } - override DotNet::Callable getARuntimeTarget(CallContext::CallContext cc) { - result = dc.getARuntimeTarget(cc) + override DataFlowCallable getARuntimeTarget(CallContext::CallContext cc) { + result = getCallableForDataFlow(dc.getARuntimeTarget(cc)) } override ControlFlow::Nodes::ElementNode getControlFlowNode() { result = cfn } @@ -306,50 +327,6 @@ class ExplicitDelegateDataFlowCall extends DelegateDataFlowCall, TExplicitDelega override Location getLocation() { result = cfn.getLocation() } } -/** - * An implicit delegate call in a call to a library method. For example, we add - * an implicit call to `M` in `new Lazy(M)` (although, technically, the delegate - * would first be called when accessing the `Value` property). - */ -class ImplicitDelegateDataFlowCall extends DelegateDataFlowCall, TImplicitDelegateCall { - private ControlFlow::Nodes::ElementNode cfn; - private DelegateArgumentToLibraryCallable arg; - - ImplicitDelegateDataFlowCall() { this = TImplicitDelegateCall(cfn, arg) } - - /** - * Holds if the underlying delegate argument is the `i`th argument of the - * call `c` targeting a library callable. For example, `M` is the `0`th - * argument of `new Lazy(M)`. - */ - predicate isArgumentOf(NonDelegateDataFlowCall c, int i) { - exists(ImplicitDelegateOutNode out | out.getControlFlowNode() = cfn | out.isArgumentOf(c, i)) - } - - /** Gets the number of parameters of the supplied delegate. */ - int getNumberOfDelegateParameters() { result = arg.getDelegateType().getNumberOfParameters() } - - /** Gets the type of the `i`th parameter of the supplied delegate. */ - Type getDelegateParameterType(int i) { result = arg.getDelegateType().getParameter(i).getType() } - - /** Gets the return type of the supplied delegate. */ - Type getDelegateReturnType() { result = arg.getDelegateType().getReturnType() } - - override DotNet::Callable getARuntimeTarget(CallContext::CallContext cc) { - result = arg.getARuntimeTarget(cc) - } - - override ControlFlow::Nodes::ElementNode getControlFlowNode() { result = cfn } - - override ImplicitDelegateOutNode getNode() { result.getControlFlowNode() = cfn } - - override Callable getEnclosingCallable() { result = cfn.getEnclosingCallable() } - - override string toString() { result = "[implicit call] " + cfn.toString() } - - override Location getLocation() { result = cfn.getLocation() } -} - /** * A call that can reach a callable, using one or more additional calls, which * reads or updates a captured variable. We model such a chain of calls as just @@ -380,7 +357,7 @@ class CilDataFlowCall extends DataFlowCall, TCilCall { CilDataFlowCall() { this = TCilCall(call) } - override DotNet::Callable getARuntimeTarget() { + override DataFlowCallable getARuntimeTarget() { // There is no dispatch library for CIL, so do not consider overrides for now result = getCallableForDataFlow(call.getTarget()) } @@ -395,3 +372,34 @@ class CilDataFlowCall extends DataFlowCall, TCilCall { override Location getLocation() { result = call.getLocation() } } + +/** + * A delegate call inside a callable with a flow summary. + * + * For example, in `ints.Select(i => i + 1)` there is a call to the delegate at + * parameter position `1` (counting the qualifier as the `0`th argument) inside + * the method `Select`. + */ +class SummaryDelegateCall extends DelegateDataFlowCall, TSummaryDelegateCall { + private SourceDeclarationCallable c; + private int pos; + + SummaryDelegateCall() { this = TSummaryDelegateCall(c, pos) } + + override DataFlowCallable getARuntimeTarget(CallContext::CallContext cc) { + exists(SummaryDelegateParameterSink p | + p = TSummaryParameterNode(c, pos) and + result = p.getARuntimeTarget(cc) + ) + } + + override ControlFlow::Nodes::ElementNode getControlFlowNode() { none() } + + override DataFlow::Node getNode() { none() } + + override Callable getEnclosingCallable() { result = c } + + override string toString() { result = "[summary] delegate call, parameter " + pos + " of " + c } + + override Location getLocation() { result = c.getLocation() } +} diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll index cb333136a48..bae73a6609d 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll @@ -17,6 +17,7 @@ private import semmle.code.csharp.frameworks.EntityFramework private import semmle.code.csharp.frameworks.NHibernate private import semmle.code.csharp.frameworks.system.Collections private import semmle.code.csharp.frameworks.system.threading.Tasks +private import semmle.code.csharp.frameworks.system.linq.Expressions abstract class NodeImpl extends Node { /** Do not call: use `getEnclosingCallable()` instead. */ @@ -321,10 +322,8 @@ module LocalFlow { * inter-procedurality or field-sensitivity. */ predicate excludeFromExposedRelations(Node n) { - n instanceof LibraryCodeNode or - n instanceof ImplicitCapturedArgumentNode or - n instanceof ImplicitDelegateOutNode or - n instanceof ImplicitDelegateArgumentNode + n instanceof Summaries::SummaryNodeImpl or + n instanceof ImplicitCapturedArgumentNode } } @@ -396,8 +395,8 @@ private predicate fieldOrPropertyStore(Expr e, Content c, Expr src, Expr q, bool f.isFieldLike() and f instanceof InstanceFieldOrProperty or - exists(LibraryFlow::AdjustedAccessPath ap | - LibraryFlow::libraryFlowSummary(_, _, ap, _, _, _) and + exists(AccessPath ap | + Summaries::summary(_, _, ap, _, _, _) and ap.contains(f.getContent()) ) ) @@ -441,8 +440,8 @@ private predicate fieldOrPropertyRead(Expr e1, Content c, FieldOrPropertyRead e2 ret.isFieldLike() and ret = e2.getTarget() or - exists(LibraryFlow::AdjustedAccessPath ap, Property target | - LibraryFlow::libraryFlowSummary(_, _, _, _, ap, _) and + exists(AccessPath ap, Property target | + Summaries::summary(_, _, _, _, ap, _) and ap.contains(ret.getContent()) and target.getGetter() = e2.(PropertyCall).getARuntimeTarget() and overridesOrImplementsSourceDecl(target, ret) @@ -520,7 +519,7 @@ private Gvn::GvnType getANonTypeParameterSubType(DataFlowTypeOrUnifiable t) { /** A collection of cached types and predicates to be evaluated in the same stage. */ cached private module Cached { - private import LibraryFlow + private import Summaries cached newtype TNode = @@ -539,20 +538,6 @@ private module Cached { v = def.getSourceVariable().getAssignable() ) } or - TImplicitDelegateOutNode( - ControlFlow::Nodes::ElementNode cfn, ControlFlow::Nodes::ElementNode call - ) { - cfn.getElement() instanceof DelegateArgumentToLibraryCallable and - any(DelegateArgumentConfiguration x).hasExprPath(_, cfn, _, call) - } or - TImplicitDelegateArgumentNode(ControlFlow::Nodes::ElementNode cfn, int i, int j) { - exists(Call call, CallableFlowSinkDelegateArg sink | - libraryFlowSummary(call, _, _, sink, _, _) and - i = sink.getDelegateIndex() and - j = sink.getDelegateParameterIndex() and - call.getArgument(i).getAControlFlowNode() = cfn - ) - } or TMallocNode(ControlFlow::Nodes::ElementNode cfn) { cfn.getElement() instanceof ObjectCreation } or TObjectInitializerNode(ControlFlow::Nodes::ElementNode cfn) { cfn.getElement().(ObjectCreation).hasInitializer() @@ -578,18 +563,48 @@ private module Cached { cfn.getElement() = fla.getQualifier() ) } or - TLibraryCodeNode( - ControlFlow::Node callCfn, CallableFlowSource source, AdjustedAccessPath sourceAp, - CallableFlowSink sink, AdjustedAccessPath sinkAp, boolean preservesValue, - LibraryCodeNodeState state - ) { - libraryFlowSummary(callCfn.getElement(), source, sourceAp, sink, sinkAp, preservesValue) and - ( - state = TLibraryCodeNodeAfterReadState(sourceAp.drop(_)) and - (sourceAp.length() > 1 or sinkAp.length() > 0 or preservesValue = false) + TSummaryParameterNode(SourceDeclarationCallable c, int i) { + exists(CallableFlowSource source | Summaries::summary(c, source, _, _, _, _) | + source instanceof CallableFlowSourceQualifier and i = -1 or - state = TLibraryCodeNodeBeforeStoreState(sinkAp.drop(_)) and - (sinkAp.length() > 1 or sourceAp.length() > 0 or preservesValue = false) + i = source.(CallableFlowSourceArg).getArgumentIndex() + or + i = source.(CallableFlowSourceDelegateArg).getArgumentIndex() + ) + or + exists(CallableFlowSink sink | Summaries::summary(c, _, _, sink, _, _) | + i = sink.(CallableFlowSinkDelegateArg).getDelegateIndex() + ) + } or + TSummaryInternalNode( + SourceDeclarationCallable c, CallableFlowSource source, AccessPath sourceAp, + CallableFlowSink sink, AccessPath sinkAp, boolean preservesValue, + SummaryInternalNodeState state + ) { + Summaries::summary(c, source, sourceAp, sink, sinkAp, preservesValue) and + ( + state = TSummaryInternalNodeAfterReadState(sourceAp.drop(_)) + or + state = TSummaryInternalNodeBeforeStoreState(sinkAp.drop(_)) + ) + } or + TSummaryReturnNode(SourceDeclarationCallable c, ReturnKind rk) { + exists(CallableFlowSink sink | + Summaries::summary(c, _, _, sink, _, _) and + rk = Summaries::toReturnKind(sink) + ) + } or + TSummaryDelegateOutNode(SourceDeclarationCallable c, int pos) { + exists(CallableFlowSourceDelegateArg source | + Summaries::summary(c, source, _, _, _, _) and + pos = source.getArgumentIndex() + ) + } or + TSummaryDelegateArgumentNode(SourceDeclarationCallable c, int delegateIndex, int parameterIndex) { + exists(CallableFlowSinkDelegateArg sink | + Summaries::summary(c, _, _, sink, _, _) and + delegateIndex = sink.getDelegateIndex() and + parameterIndex = sink.getDelegateParameterIndex() ) } or TParamsArgumentNode(ControlFlow::Node callCfn) { @@ -608,7 +623,7 @@ private module Cached { or LocalFlow::localFlowCapturedVarStep(nodeFrom, nodeTo) or - LibraryFlow::localStepLibrary(nodeFrom, nodeTo, true) + Summaries::summaryLocalStep(nodeFrom, nodeTo, true) or nodeTo.(ObjectCreationNode).getPreUpdateNode() = nodeFrom.(ObjectInitializerNode) } @@ -628,9 +643,7 @@ private module Cached { or // Simple flow through library code is included in the exposed local // step relation, even though flow is technically inter-procedural - LibraryFlow::localStepLibrary(nodeFrom, nodeTo, true) and - not LocalFlow::excludeFromExposedRelations(nodeFrom) and - not LocalFlow::excludeFromExposedRelations(nodeTo) + Summaries::summaryThroughStep(nodeFrom, nodeTo, true) } /** @@ -677,7 +690,7 @@ private module Cached { c instanceof ElementContent ) or - storeStepLibrary(node1, c, node2) + summaryStoreStep(node1, c, node2) } pragma[nomagic] @@ -711,7 +724,7 @@ private module Cached { c = getResultContent() ) or - readStepLibrary(node1, c, node2) + summaryReadStep(node1, c, node2) } /** @@ -725,10 +738,10 @@ private module Cached { or fieldOrPropertyStore(_, c, _, n.(ObjectInitializerNode).getInitializer(), false) or - storeStepLibrary(n, c, _) and + summaryStoreStep(n, c, _) and not c instanceof ElementContent or - clearsContentLibrary(n, c) + summaryClearsContent(n, c) } /** @@ -784,6 +797,14 @@ private module Cached { ) } + cached + predicate qualifierOutNode(DataFlowCall call, Node n) { + n.(ExprPostUpdateNode).getPreUpdateNode().(ExplicitArgumentNode).argumentOf(call, -1) + or + any(ObjectOrCollectionInitializerConfiguration x) + .hasExprPath(_, n.(ExprNode).getControlFlowNode(), _, call.getControlFlowNode()) + } + cached predicate castNode(Node n) { n.asExpr() instanceof Cast @@ -806,13 +827,9 @@ private module Cached { or n instanceof ImplicitCapturedArgumentNode or - n instanceof ImplicitDelegateOutNode - or - n instanceof ImplicitDelegateArgumentNode - or n instanceof MallocNode or - n instanceof LibraryCodeNode + n instanceof Summaries::SummaryNodeImpl or n instanceof ParamsArgumentNode } @@ -861,7 +878,8 @@ private module ParameterNodes { private DotNet::Parameter parameter; ExplicitParameterNode() { - explicitParameterNode(this, parameter) or + explicitParameterNode(this, parameter) + or this = TCilParameterNode(parameter) } @@ -869,7 +887,7 @@ private module ParameterNodes { override predicate isParameterOf(DataFlowCallable c, int i) { c.getParameter(i) = parameter } - override DotNet::Callable getEnclosingCallableImpl() { result = parameter.getCallable() } + override DataFlowCallable getEnclosingCallableImpl() { result = parameter.getCallable() } override DotNet::Type getTypeImpl() { result = parameter.getType() } @@ -968,11 +986,52 @@ private module ParameterNodes { c = this.getEnclosingCallable() } } + + /** A parameter node for a callable with a flow summary. */ + class SummaryParameterNode extends ParameterNodeImpl, Summaries::SummaryNodeImpl, + TSummaryParameterNode { + private SourceDeclarationCallable sdc; + private int i; + + SummaryParameterNode() { this = TSummaryParameterNode(sdc, i) } + + override Parameter getParameter() { result = sdc.getParameter(i) } + + override predicate isParameterOf(DataFlowCallable c, int pos) { + c = sdc and + pos = i + } + + override Callable getEnclosingCallableImpl() { result = sdc } + + override Type getTypeImpl() { + result = sdc.getParameter(i).getType() + or + i = -1 and + result = sdc.getDeclaringType() + } + + override ControlFlow::Node getControlFlowNodeImpl() { none() } + + override Location getLocationImpl() { + result = sdc.getParameter(i).getLocation() + or + i = -1 and + result = sdc.getLocation() + } + + override string toStringImpl() { + result = "[summary] " + sdc.getParameter(i) + or + i = -1 and + result = "[summary] this" + } + } } import ParameterNodes -/** A data flow node that represents a call argument. */ +/** A data-flow node that represents a call argument. */ abstract class ArgumentNode extends Node { /** Holds if this argument occurs at the given position in the given call. */ cached @@ -983,21 +1042,6 @@ abstract class ArgumentNode extends Node { } private module ArgumentNodes { - class DelegateArgumentConfiguration extends ControlFlowReachabilityConfiguration { - DelegateArgumentConfiguration() { this = "DelegateArgumentConfiguration" } - - override predicate candidate( - Expr e1, Expr e2, ControlFlowElement scope, boolean exactScope, boolean isSuccessor - ) { - exists(DelegateArgumentToLibraryCallable arg | e1 = arg.getCall().getAnArgument() | - e2 = arg.getCall() and - scope = e2 and - exactScope = false and - isSuccessor = true - ) - } - } - private class ArgumentConfiguration extends ControlFlowReachabilityConfiguration { ArgumentConfiguration() { this = "ArgumentConfiguration" } @@ -1011,8 +1055,8 @@ private module ArgumentNodes { } } - /** A data flow node that represents an explicit call argument. */ - private class ExplicitArgumentNode extends ArgumentNode { + /** A data-flow node that represents an explicit call argument. */ + class ExplicitArgumentNode extends ArgumentNode { ExplicitArgumentNode() { this.asExpr() instanceof Argument or @@ -1071,22 +1115,11 @@ private module ArgumentNodes { override predicate argumentOf(DataFlowCall call, int pos) { exists(ImplicitCapturedParameterNode p, boolean additionalCalls | this.flowsInto(p, additionalCalls) and - p.isParameterOf(call.getARuntimeTarget(), pos) - | + p.isParameterOf(call.getARuntimeTarget(), pos) and + call.getControlFlowNode() = cfn and if call instanceof TransitiveCapturedDataFlowCall - then additionalCalls = true and call.getControlFlowNode() = cfn - else ( - additionalCalls = false and - ( - call.getControlFlowNode() = cfn - or - exists(DataFlowCall parent | - call.(ImplicitDelegateDataFlowCall).isArgumentOf(parent, _) - | - parent.getControlFlowNode() = cfn - ) - ) - ) + then additionalCalls = true + else additionalCalls = false ) } @@ -1127,46 +1160,7 @@ private module ArgumentNodes { } /** - * A data flow node that represents an implicit argument of an implicit delegate - * call in library code. For example, in - * - * ```csharp - * x.Select(Foo); - * ``` - * - * `x` is an implicit argument of the implicit call to `Foo`. - */ - class ImplicitDelegateArgumentNode extends ArgumentNode, NodeImpl, TImplicitDelegateArgumentNode { - private ControlFlow::Node cfn; - private int delegateIndex; - private int parameterIndex; - - ImplicitDelegateArgumentNode() { - this = TImplicitDelegateArgumentNode(cfn, delegateIndex, parameterIndex) - } - - private ImplicitDelegateDataFlowCall getDelegateCall() { result.getControlFlowNode() = cfn } - - override predicate argumentOf(DataFlowCall call, int pos) { - call = this.getDelegateCall() and - pos = parameterIndex - } - - override Callable getEnclosingCallableImpl() { result = cfn.getEnclosingCallable() } - - override Type getTypeImpl() { - result = this.getDelegateCall().getDelegateParameterType(parameterIndex) - } - - override ControlFlow::Node getControlFlowNodeImpl() { none() } - - override Location getLocationImpl() { result = cfn.getLocation() } - - override string toStringImpl() { result = "[implicit argument " + parameterIndex + "] " + cfn } - } - - /** - * A data flow node that represents the implicit array creation in a call to a + * A data-flow node that represents the implicit array creation in a call to a * callable with a `params` parameter. For example, there is an implicit array * creation `new [] { "a", "b", "c" }` in * @@ -1203,11 +1197,55 @@ private module ArgumentNodes { override string toStringImpl() { result = "[implicit array creation] " + callCfn } } + + /** + * An argument node inside a callable with a flow summary, where the argument is + * passed to a supplied delegate. For example, in `ints.Select(Foo)` there is a + * node that represents the argument of the call to `Foo` inside `Select`. + */ + class SummaryDelegateArgumentNode extends ArgumentNode, Summaries::SummaryNodeImpl, + TSummaryDelegateArgumentNode { + private SourceDeclarationCallable c; + private int delegateIndex; + private int parameterIndex; + + SummaryDelegateArgumentNode() { + this = TSummaryDelegateArgumentNode(c, delegateIndex, parameterIndex) + } + + override DataFlowCallable getEnclosingCallableImpl() { result = c } + + override DotNet::Type getTypeImpl() { + result = + c + .getParameter(delegateIndex) + .getType() + .(SystemLinqExpressions::DelegateExtType) + .getDelegateType() + .getParameter(parameterIndex) + .getType() + } + + override ControlFlow::Node getControlFlowNodeImpl() { none() } + + override Location getLocationImpl() { result = c.getLocation() } + + override string toStringImpl() { + result = + "[summary] argument " + parameterIndex + " of delegate call, parameter " + parameterIndex + + " of " + c + } + + override predicate argumentOf(DataFlowCall call, int pos) { + call = TSummaryDelegateCall(c, delegateIndex) and + pos = parameterIndex + } + } } import ArgumentNodes -/** A data flow node that represents a value returned by a callable. */ +/** A data-flow node that represents a value returned by a callable. */ abstract class ReturnNode extends Node { /** Gets the kind of this return node. */ abstract ReturnKind getKind(); @@ -1215,7 +1253,7 @@ abstract class ReturnNode extends Node { private module ReturnNodes { /** - * A data flow node that represents an expression returned by a callable, + * A data-flow node that represents an expression returned by a callable, * either using a (`yield`) `return` statement or an expression body (`=>`). */ class ExprReturnNode extends ReturnNode, ExprNode { @@ -1233,7 +1271,7 @@ private module ReturnNodes { } /** - * A data flow node that represents an assignment to an `out` or a `ref` + * A data-flow node that represents an assignment to an `out` or a `ref` * parameter. */ class OutRefReturnNode extends ReturnNode, SsaDefinitionNode { @@ -1308,11 +1346,39 @@ private module ReturnNodes { result.getVariable() = edef.getSourceVariable().getAssignable() } } + + /** A return node for a callable with a flow summary. */ + class SummaryReturnNode extends ReturnNode, Summaries::SummaryNodeImpl, TSummaryReturnNode { + private SourceDeclarationCallable sdc; + private ReturnKind rk; + + SummaryReturnNode() { this = TSummaryReturnNode(sdc, rk) } + + override Callable getEnclosingCallableImpl() { result = sdc } + + override DotNet::Type getTypeImpl() { + rk instanceof NormalReturnKind and + result in [sdc.getReturnType(), sdc.(Constructor).getDeclaringType()] + or + rk instanceof QualifierReturnKind and + result = sdc.getDeclaringType() + or + result = sdc.getParameter(rk.(OutRefReturnKind).getPosition()).getType() + } + + override ControlFlow::Node getControlFlowNodeImpl() { none() } + + override Location getLocationImpl() { result = sdc.getLocation() } + + override string toStringImpl() { result = "[summary] return of kind " + rk + " inside " + sdc } + + override ReturnKind getKind() { result = rk } + } } import ReturnNodes -/** A data flow node that represents the output of a call. */ +/** A data-flow node that represents the output of a call. */ abstract class OutNode extends Node { /** Gets the underlying call, where this node is a corresponding output of kind `kind`. */ cached @@ -1344,7 +1410,7 @@ private module OutNodes { } /** - * A data flow node that reads a value returned directly by a callable, + * A data-flow node that reads a value returned directly by a callable, * either via a C# call or a CIL call. */ class ExprOutNode extends OutNode, ExprNode { @@ -1370,8 +1436,44 @@ private module OutNodes { } } + class ObjectOrCollectionInitializerConfiguration extends ControlFlowReachabilityConfiguration { + ObjectOrCollectionInitializerConfiguration() { + this = "ObjectOrCollectionInitializerConfiguration" + } + + override predicate candidate( + Expr e1, Expr e2, ControlFlowElement scope, boolean exactScope, boolean isSuccessor + ) { + exactScope = false and + scope = e1 and + isSuccessor = false and + ( + // E.g. `new Dictionary{ {0, "a"}, {1, "b"} }` + e1.(CollectionInitializer).getAnElementInitializer() = e2 + or + // E.g. `new Dictionary() { [0] = "a", [1] = "b" }` + e1.(ObjectInitializer).getAMemberInitializer().getLValue() = e2 + ) + } + } + /** - * A data flow node that reads a value returned implicitly by a callable + * A data-flow node that contains a value returned by a callable, by writing + * to the qualifier of the call. + */ + private class QualifierOutNode extends OutNode, Node { + private DataFlowCall call; + + QualifierOutNode() { qualifierOutNode(call, this) } + + override DataFlowCall getCall(ReturnKind kind) { + result = call and + kind instanceof QualifierReturnKind + } + } + + /** + * A data-flow node that reads a value returned implicitly by a callable * using a captured variable. */ class CapturedOutNode extends OutNode, SsaDefinitionNode { @@ -1384,10 +1486,8 @@ private module OutNodes { | additionalCalls = false and call = csharpCall(_, cfn) or - additionalCalls = false and - call.(ImplicitDelegateDataFlowCall).isArgumentOf(csharpCall(_, cfn), _) - or - additionalCalls = true and call = TTransitiveCapturedCall(cfn, n.getEnclosingCallable()) + additionalCalls = true and + call = TTransitiveCapturedCall(cfn, n.getEnclosingCallable()) ) } @@ -1399,7 +1499,7 @@ private module OutNodes { } /** - * A data flow node that reads a value returned by a callable using an + * A data-flow node that reads a value returned by a callable using an * `out` or `ref` parameter. */ class ParamOutNode extends OutNode, AssignableDefinitionNode { @@ -1418,566 +1518,219 @@ private module OutNodes { } /** - * A data flow node that represents the output of an implicit delegate call, - * in a call to a library method. For example, the output from the implicit - * call to `M` in `new Lazy(M)`. + * An output node inside a callable with a flow summary, where the output is the + * result of calling a supplied delegate. For example, in `ints.Select(Foo)` there + * is a node that represents the output of calling `Foo` inside `Select`. */ - class ImplicitDelegateOutNode extends OutNode, NodeImpl, TImplicitDelegateOutNode { - private ControlFlow::Nodes::ElementNode cfn; - private ControlFlow::Nodes::ElementNode call; + private class SummaryDelegateOutNode extends OutNode, Summaries::SummaryNodeImpl, + TSummaryDelegateOutNode { + private SourceDeclarationCallable c; + private int pos; - ImplicitDelegateOutNode() { this = TImplicitDelegateOutNode(cfn, call) } + SummaryDelegateOutNode() { this = TSummaryDelegateOutNode(c, pos) } - /** - * Holds if the underlying delegate argument is the `i`th argument of the - * call `c` targeting a library callable. For example, `M` is the `0`th - * argument of `new Lazy(M)`. - */ - predicate isArgumentOf(DataFlowCall c, int i) { - c.getControlFlowNode() = call and - call.getElement().(Call).getArgument(i) = cfn.getElement() + override Callable getEnclosingCallableImpl() { result = c } + + override DotNet::Type getTypeImpl() { + result = + c + .getParameter(pos) + .getType() + .(SystemLinqExpressions::DelegateExtType) + .getDelegateType() + .getReturnType() } - override ControlFlow::Nodes::ElementNode getControlFlowNodeImpl() { result = cfn } + override ControlFlow::Node getControlFlowNodeImpl() { none() } - override ImplicitDelegateDataFlowCall getCall(ReturnKind kind) { - result.getNode() = this and - ( - kind instanceof NormalReturnKind and - not result.getDelegateReturnType() instanceof VoidType - or - kind instanceof YieldReturnKind and - result.getDelegateReturnType() instanceof YieldReturnType - ) + override Location getLocationImpl() { result = c.getLocation() } + + override string toStringImpl() { + result = "[summary] output from delegate call, parameter " + pos + " of " + c + "]" } - override Callable getEnclosingCallableImpl() { result = cfn.getEnclosingCallable() } - - override Type getTypeImpl() { - exists(ImplicitDelegateDataFlowCall c | c.getNode() = this | - result = c.getDelegateReturnType() - ) + override SummaryDelegateCall getCall(ReturnKind kind) { + result = TSummaryDelegateCall(c, pos) and + kind instanceof NormalReturnKind } - - override Location getLocationImpl() { result = cfn.getLocation() } - - override string toStringImpl() { result = "[output] " + cfn } } } import OutNodes /** - * Provides predicates related to flow through library code, based on - * the flow summaries in `LibraryTypeDataFlow.qll`. + * Provides predicates for interpreting flow summaries defined in + * `LibraryTypeDataFlow.qll`. */ -module LibraryFlow { - pragma[nomagic] - private ValueOrRefType getPreciseSourceProperty0( - Call call, CallableFlowSource source, AccessPath sourceAp, Property p, AccessPath sourceApTail - ) { - exists(LibraryTypeDataFlow ltdf, Property p0 | - ltdf.callableFlow(source, sourceAp, _, _, call.getTarget().getSourceDeclaration(), _) and - sourceAp.getHead().(PropertyContent).getProperty() = p0 and - sourceAp.getTail() = sourceApTail and - overridesOrImplementsSourceDecl(p, p0) and - result = source.getSourceType(call) - ) - } - - /** - * Gets a precise source property for source `source` and access path `sourceAp`, - * in the context of `call`. For example, in - * - * ```csharp - * var list = new List(); - * var count = list.Count(); - * ``` - * - * the step from `list` to `list.Count()`, which may be modeled as a read of - * the `Count` property from `ICollection`, can be strengthened to be a - * read of the `Count` property from `List`. - */ - pragma[nomagic] - private Property getPreciseSourceProperty( - Call call, CallableFlowSource source, AccessPath sourceAp, AccessPath sourceApTail - ) { - getPreciseSourceProperty0(call, source, sourceAp, result, sourceApTail).hasMember(result) - } - - pragma[nomagic] - private ValueOrRefType getPreciseSinkProperty0( - Call call, CallableFlowSink sink, AccessPath sinkAp, Property p, AccessPath sinkApTail - ) { - exists(LibraryTypeDataFlow ltdf, Property p0 | - ltdf.callableFlow(_, _, sink, sinkAp, call.getTarget().getSourceDeclaration(), _) and - sinkAp.getHead().(PropertyContent).getProperty() = p0 and - sinkAp.getTail() = sinkApTail and - overridesOrImplementsSourceDecl(p, p0) and - result = sink.getSinkType(call) - ) - } - - /** - * Gets a precise sink property for sink `sink` and access path `sinkAp`, - * in the context of `call`. For example, in - * - * ```csharp - * var list = new List(); - * list.Add("taint"); - * var enumerator = list.getEnumerator(); - * ``` - * - * the step from `list` to `list.getEnumerator()`, which may be modeled as a - * read of a collection element followed by a store into the `Current` - * property, can be strengthened to be a store into the `Current` property - * from `List.Enumerator`, rather than the generic `Current` property - * from `IEnumerator`. - */ - pragma[nomagic] - private Property getPreciseSinkProperty( - Call call, CallableFlowSink sink, AccessPath sinkAp, AccessPath sinkApTail - ) { - getPreciseSinkProperty0(call, sink, sinkAp, result, sinkApTail).hasMember(result) - } - - predicate adjustSourceHead( - Call call, CallableFlowSource source, AccessPath sourceAp0, AccessPath sourceApTail, - PropertyContent p - ) { - overridesOrImplementsSourceDecl(p.getProperty(), - getPreciseSourceProperty(call, source, sourceAp0, sourceApTail).getSourceDeclaration()) - } - - predicate adjustSinkHead( - Call call, CallableFlowSink sink, AccessPath sinkAp0, AccessPath sinkApTail, PropertyContent p - ) { - p.getProperty() = getPreciseSinkProperty(call, sink, sinkAp0, sinkApTail).getSourceDeclaration() - } - - private newtype TAdjustedAccessPath = - TOriginalAccessPath(AccessPath ap) or - THeadAdjustedAccessPath(PropertyContent head, AccessPath tail) { - adjustSourceHead(_, _, _, tail, head) - or - adjustSinkHead(_, _, _, tail, head) - } - - /** - * An access path used in a library-code flow-summary, where the head of the path - * may have been adjusted. For example, in - * - * ```csharp - * var list = new List(); - * list.Add("taint"); - * var enumerator = list.getEnumerator(); - * ``` - * - * the step from `list` to `list.getEnumerator()`, which may be modeled as a - * read of a collection element followed by a store into the `Current` - * property, can be strengthened to be a store into the `Current` property - * from `List.Enumerator`, rather than the generic `Current` property - * from `IEnumerator`. - */ - abstract class AdjustedAccessPath extends TAdjustedAccessPath { - /** Gets the head of this access path, if any. */ - abstract Content getHead(); - - /** Gets the tail of this access path, if any. */ - abstract AdjustedAccessPath getTail(); - - /** Gets the length of this access path. */ - abstract int length(); - - /** Gets the access path obtained by dropping the first `i` elements, if any. */ - abstract AdjustedAccessPath drop(int i); - - /** Holds if this access path contains content `c`. */ - predicate contains(Content c) { c = this.drop(_).getHead() } - - /** Gets a textual representation of this access path. */ - string toString() { - exists(Content head, AdjustedAccessPath tail | - head = this.getHead() and - tail = this.getTail() and - if tail.length() = 0 then result = head.toString() else result = head + ", " + tail - ) - or - this.length() = 0 and - result = "" - } - } - - private class OriginalAccessPath extends AdjustedAccessPath, TOriginalAccessPath { - private AccessPath ap; - - OriginalAccessPath() { this = TOriginalAccessPath(ap) } - - override Content getHead() { result = ap.getHead() } - - override AdjustedAccessPath getTail() { result = TOriginalAccessPath(ap.getTail()) } - - override int length() { result = ap.length() } - - override AdjustedAccessPath drop(int i) { result = TOriginalAccessPath(ap.drop(i)) } - } - - private class HeadAdjustedAccessPath extends AdjustedAccessPath, THeadAdjustedAccessPath { - private PropertyContent head; - private AccessPath tail; - - HeadAdjustedAccessPath() { this = THeadAdjustedAccessPath(head, tail) } - - override Content getHead() { result = head } - - override AdjustedAccessPath getTail() { result = TOriginalAccessPath(tail) } - - override int length() { result = 1 + tail.length() } - - override AdjustedAccessPath drop(int i) { - i = 0 and result = this - or - result = TOriginalAccessPath(tail.drop(i - 1)) - } - } - - module AdjustedAccessPath { - AdjustedAccessPath empty() { result.length() = 0 } - - AdjustedAccessPath singleton(Content c) { result.getHead() = c and result.length() = 1 } - } - - pragma[nomagic] - private predicate callableFlow( - CallableFlowSource source, AccessPath sourceAp, boolean adjustSourceAp, CallableFlowSink sink, - AccessPath sinkAp, boolean adjustSinkAp, SourceDeclarationCallable c, boolean preservesValue - ) { - any(LibraryTypeDataFlow ltdf).callableFlow(source, sourceAp, sink, sinkAp, c, preservesValue) and - ( - if sourceAp.getHead() instanceof PropertyContent - then adjustSourceAp = true - else adjustSourceAp = false - ) and - if sinkAp.getHead() instanceof PropertyContent - then adjustSinkAp = true - else adjustSinkAp = false - } +module Summaries { + /** A data-flow node used to interpret a flow summary. */ + abstract class SummaryNodeImpl extends NodeImpl { } /** * Holds if data can flow from a node of kind `source` to a node of kind `sink`, - * using a call to a library callable. + * using a call to a callable with a flow summary. * * `sourceAp` describes the contents of the source node that flows to the sink * (if any), and `sinkAp` describes the contents of the sink that it flows to * (if any). */ pragma[nomagic] - predicate libraryFlowSummary( - Call call, CallableFlowSource source, AdjustedAccessPath sourceAp, CallableFlowSink sink, - AdjustedAccessPath sinkAp, boolean preservesValue + predicate summary( + SourceDeclarationCallable c, CallableFlowSource source, AccessPath sourceAp, + CallableFlowSink sink, AccessPath sinkAp, boolean preservesValue ) { - exists(SourceDeclarationCallable c | c = call.getTarget().getSourceDeclaration() | - any(LibraryTypeDataFlow ltdf).callableFlow(source, sink, c, preservesValue) and - sourceAp = TOriginalAccessPath(AccessPath::empty()) and - sinkAp = TOriginalAccessPath(AccessPath::empty()) - or - exists( - AccessPath sourceAp0, boolean adjustSourceAp, AccessPath sinkAp0, boolean adjustSinkAp - | - callableFlow(source, sourceAp0, adjustSourceAp, sink, sinkAp0, adjustSinkAp, c, - preservesValue) and - ( - adjustSourceAp = false and - sourceAp = TOriginalAccessPath(sourceAp0) - or - adjustSourceAp = true and - exists(PropertyContent p, AccessPath sourceApTail | - adjustSourceHead(call, source, sourceAp0, sourceApTail, p) and - sourceAp = THeadAdjustedAccessPath(p, sourceApTail) - ) - ) and - ( - adjustSinkAp = false and - sinkAp = TOriginalAccessPath(sinkAp0) - or - adjustSinkAp = true and - exists(PropertyContent p, AccessPath sinkApTail | - adjustSinkHead(call, sink, sinkAp0, sinkApTail, p) and - sinkAp = THeadAdjustedAccessPath(p, sinkApTail) - ) - ) - ) - ) + any(LibraryTypeDataFlow ltdf).callableFlow(source, sink, c, preservesValue) and + sourceAp = AccessPath::empty() and + sinkAp = AccessPath::empty() + or + any(LibraryTypeDataFlow ltdf).callableFlow(source, sourceAp, sink, sinkAp, c, preservesValue) } - private class LibrarySourceConfiguration extends ControlFlowReachabilityConfiguration { - LibrarySourceConfiguration() { this = "LibrarySourceConfiguration" } - - override predicate candidate( - Expr e1, Expr e2, ControlFlowElement scope, boolean exactScope, boolean isSuccessor - ) { - exists(CallableFlowSource source | - libraryFlowSummary(e2, source, _, _, _, _) and - e1 = source.getSource(e2) and - scope = e2 and - exactScope = false and - isSuccessor = true - ) - } + /** Gets the return kind that matches `sink`, if any. */ + ReturnKind toReturnKind(CallableFlowSink sink) { + sink instanceof CallableFlowSinkQualifier and result instanceof QualifierReturnKind + or + sink instanceof CallableFlowSinkReturn and result instanceof NormalReturnKind + or + sink.(CallableFlowSinkArg).getArgumentIndex() = result.(OutRefReturnKind).getPosition() } - private class LibrarySinkConfiguration extends ControlFlowReachabilityConfiguration { - LibrarySinkConfiguration() { this = "LibrarySinkConfiguration" } - - override predicate candidate( - Expr e1, Expr e2, ControlFlowElement scope, boolean exactScope, boolean isSuccessor - ) { - exists(CallableFlowSink sink | - libraryFlowSummary(e1, _, _, sink, _, _) and - e2 = sink.getSink(e1) and - exactScope = false and - if e2 instanceof ObjectOrCollectionInitializer - then scope = e2 and isSuccessor = true - else ( - scope = e1 and isSuccessor = false - ) - ) - } - - override predicate candidateDef( - Expr e, AssignableDefinition def, ControlFlowElement scope, boolean exactScope, - boolean isSuccessor - ) { - exists(CallableFlowSinkArg sink | - libraryFlowSummary(e, _, _, sink, _, _) and - scope = e and - exactScope = false and - isSuccessor = true and - def.getTargetAccess() = sink.getArgument(e) and - def instanceof AssignableDefinitions::OutRefDefinition - ) - } - } - - newtype TLibraryCodeNodeState = - TLibraryCodeNodeAfterReadState(AdjustedAccessPath ap) { ap.length() > 0 } or - TLibraryCodeNodeBeforeStoreState(AdjustedAccessPath ap) { ap.length() > 0 } + newtype TSummaryInternalNodeState = + TSummaryInternalNodeAfterReadState(AccessPath ap) { ap.length() > 0 } or + TSummaryInternalNodeBeforeStoreState(AccessPath ap) { ap.length() > 0 } /** * A state used to break up (complex) flow summaries for library code into atomic * flow steps. For a flow summary with source access path `sourceAp` and sink * access path `sinkAp`, the following states are used: * - * - `TLibraryCodeNodeAfterReadState(AccessPath ap)`: this state represents + * - `TSummaryInternalNodeAfterReadState(AccessPath ap)`: this state represents * that the head of `ap` has been read from, where `ap` is a suffix of * `sourceAp`. - * - `TLibraryCodeNodeBeforeStoreState(AccessPath ap)`: this state represents + * - `TSummaryInternalNodeBeforeStoreState(AccessPath ap)`: this state represents * that the head of `ap` is to be stored into next, where `ap` is a suffix of * `sinkAp`. * * The state machine for flow summaries has no branching, hence from the entry * state there is a unique path to the exit state. */ - class LibraryCodeNodeState extends TLibraryCodeNodeState { + class SummaryInternalNodeState extends TSummaryInternalNodeState { string toString() { - exists(AdjustedAccessPath ap | - this = TLibraryCodeNodeAfterReadState(ap) and + exists(AccessPath ap | + this = TSummaryInternalNodeAfterReadState(ap) and result = "after read: " + ap ) or - exists(AdjustedAccessPath ap | - this = TLibraryCodeNodeBeforeStoreState(ap) and + exists(AccessPath ap | + this = TSummaryInternalNodeBeforeStoreState(ap) and result = "before store: " + ap ) } /** Holds if this state represents the state after the last read. */ predicate isLastReadState() { - this = TLibraryCodeNodeAfterReadState(AdjustedAccessPath::singleton(_)) + this = TSummaryInternalNodeAfterReadState(AccessPath::singleton(_)) } /** Holds if this state represents the state before the first store. */ predicate isFirstStoreState() { - this = TLibraryCodeNodeBeforeStoreState(AdjustedAccessPath::singleton(_)) + this = TSummaryInternalNodeBeforeStoreState(AccessPath::singleton(_)) } } - /** - * Holds if `entry` is an entry node of kind `source` for the call `callCfn`, which - * targets a library callable with a flow summary. - */ - private predicate entry(Node entry, ControlFlow::Node callCfn, CallableFlowSource source) { - // The source is either an argument or a qualifier, for example - // `s` in `int.Parse(s)` - exists(LibrarySourceConfiguration x, Call call | - callCfn = call.getAControlFlowNode() and - x.hasExprPath(source.getSource(call), entry.(ExprNode).getControlFlowNode(), _, callCfn) + private NodeImpl getSourceNode(SourceDeclarationCallable c, CallableFlowSource source) { + exists(int i | result = TSummaryParameterNode(c, i) | + source instanceof CallableFlowSourceQualifier and i = -1 + or + i = source.(CallableFlowSourceArg).getArgumentIndex() ) or - // The source is the output of a supplied delegate argument, for - // example the output of `Foo` in `new Lazy(Foo)` - exists(DataFlowCall call, int pos | - pos = source.(CallableFlowSourceDelegateArg).getArgumentIndex() and - entry.(ImplicitDelegateOutNode).isArgumentOf(call, pos) and - callCfn = call.getControlFlowNode() - ) + result = TSummaryDelegateOutNode(c, source.(CallableFlowSourceDelegateArg).getArgumentIndex()) } - /** - * Holds if `exit` is an exit node of kind `sink` for the call `callCfn`, which - * targets a library callable with a flow summary. - */ - private predicate exit(Node exit, ControlFlow::Node callCfn, CallableFlowSink sink) { - exists(LibrarySinkConfiguration x, Call call, ExprNode e | - callCfn = call.getAControlFlowNode() and - x.hasExprPath(_, callCfn, sink.getSink(call), e.getControlFlowNode()) - | - // The sink is an ordinary return value, for example `int.Parse(s)` - sink instanceof CallableFlowSinkReturn and - exit = e - or - // The sink is a qualifier, for example `list` in `list.Add(x)` - sink instanceof CallableFlowSinkQualifier and - if e.getExpr() instanceof ObjectOrCollectionInitializer - then exit = e - else exit.(ExprPostUpdateNode).getPreUpdateNode() = e - ) + private NodeImpl getSinkNode(SourceDeclarationCallable c, CallableFlowSink sink) { + result = TSummaryReturnNode(c, toReturnKind(sink)) or - // The sink is an `out`/`ref` argument, for example `out i` in - // `int.TryParse(s, out i)` - exists(LibrarySinkConfiguration x, OutRefReturnKind k | - exit = - any(ParamOutNode out | - out.getCall(k).getControlFlowNode() = callCfn and - sink.(CallableFlowSinkArg).getArgumentIndex() = k.getPosition() and - x.hasDefPath(_, callCfn, out.getDefinition(), _) - ) - ) - or - // The sink is a parameter of a supplied delegate argument, for example - // the parameter of `Foo` in `list.Select(Foo)`. - // - // This is implemented using a node that represents the implicit argument - // (`ImplicitDelegateArgumentNode`) of the implicit call - // (`ImplicitDelegateDataFlowCall`) to `Foo`. - exists( - DataFlowCall call, ImplicitDelegateDataFlowCall dcall, int delegateIndex, int parameterIndex - | - sink = - any(CallableFlowSinkDelegateArg s | - delegateIndex = s.getDelegateIndex() and - parameterIndex = s.getDelegateParameterIndex() - ) and - exit = TImplicitDelegateArgumentNode(dcall.getControlFlowNode(), _, parameterIndex) and - dcall.isArgumentOf(call, delegateIndex) and - callCfn = call.getControlFlowNode() - ) + sink = + any(CallableFlowSinkDelegateArg s | + result = + TSummaryDelegateArgumentNode(c, s.getDelegateIndex(), s.getDelegateParameterIndex()) + ) } /** * Holds if there is a local step from `pred` to `succ`, which is synthesized - * from a library-code flow summary. + * from a flow summary. */ - predicate localStepLibrary(Node pred, Node succ, boolean preservesValue) { + predicate summaryLocalStep(Node pred, Node succ, boolean preservesValue) { exists( - ControlFlow::Node callCfn, CallableFlowSource source, AdjustedAccessPath sourceAp, - CallableFlowSink sink, AdjustedAccessPath sinkAp + SourceDeclarationCallable c, CallableFlowSource source, AccessPath sourceAp, + CallableFlowSink sink, AccessPath sinkAp | - libraryFlowSummary(callCfn.getElement(), source, sourceAp, sink, sinkAp, preservesValue) + pred = getSourceNode(c, source) | // Simple flow summary without reads or stores - sourceAp = AdjustedAccessPath::empty() and - sinkAp = AdjustedAccessPath::empty() and - entry(pred, callCfn, source) and - exit(succ, callCfn, sink) + sourceAp = AccessPath::empty() and + sinkAp = AccessPath::empty() and + summary(c, source, sourceAp, sink, sinkAp, preservesValue) and + succ = getSinkNode(c, sink) or - // Entry step for a complex summary with no reads and (1) multiple stores, or - // (2) at least one store and non-value-preservation - exists(LibraryCodeNodeState succState | - sourceAp = AdjustedAccessPath::empty() and - entry(pred, callCfn, source) and + // Flow summary with stores but no reads + exists(SummaryInternalNodeState succState | + sourceAp = AccessPath::empty() and succState.isFirstStoreState() and - succ = TLibraryCodeNode(callCfn, source, sourceAp, sink, sinkAp, preservesValue, succState) - ) - or - // Exit step for a complex summary with no stores and (1) multiple reads, or - // (2) at least one read and non-value-preservation - exists(LibraryCodeNodeState predState | - sinkAp = AdjustedAccessPath::empty() and - predState.isLastReadState() and - pred = TLibraryCodeNode(callCfn, source, sourceAp, sink, sinkAp, preservesValue, predState) and - exit(succ, callCfn, sink) + succ = TSummaryInternalNode(c, source, sourceAp, sink, sinkAp, preservesValue, succState) ) ) or + // Exit step after last read (no stores) + exists( + SourceDeclarationCallable c, SummaryInternalNodeState predState, CallableFlowSink sink, + AccessPath sinkAp + | + sinkAp = AccessPath::empty() and + predState.isLastReadState() and + pred = TSummaryInternalNode(c, _, _, sink, sinkAp, preservesValue, predState) and + succ = getSinkNode(c, sink) + ) + or // Internal step for complex flow summaries with both reads and writes exists( - ControlFlow::Node callCfn, CallableFlowSource source, AdjustedAccessPath sourceAp, - CallableFlowSink sink, AdjustedAccessPath sinkAp, LibraryCodeNodeState predState, - LibraryCodeNodeState succState + SourceDeclarationCallable c, CallableFlowSource source, AccessPath sourceAp, + CallableFlowSink sink, AccessPath sinkAp, SummaryInternalNodeState predState, + SummaryInternalNodeState succState | predState.isLastReadState() and - pred = TLibraryCodeNode(callCfn, source, sourceAp, sink, sinkAp, preservesValue, predState) and + pred = TSummaryInternalNode(c, source, sourceAp, sink, sinkAp, preservesValue, predState) and succState.isFirstStoreState() and - succ = TLibraryCodeNode(callCfn, source, sourceAp, sink, sinkAp, preservesValue, succState) - ) - } - - /** - * Holds if there is a store of `pred` into content `c` of `succ`, which happens - * via library code. - */ - predicate setterLibrary(Node pred, Content c, Node succ, boolean preservesValue) { - exists(ControlFlow::Node callCfn, CallableFlowSource source, CallableFlowSink sink | - libraryFlowSummary(callCfn.getElement(), source, AdjustedAccessPath::empty(), sink, - AdjustedAccessPath::singleton(c), preservesValue) - | - entry(pred, callCfn, source) and - exit(succ, callCfn, sink) + succ = TSummaryInternalNode(c, source, sourceAp, sink, sinkAp, preservesValue, succState) ) } /** * Holds if data can flow from `pred` to `succ` via an assignment to - * content `c`, using library code. + * content `c`, using a flow summary. */ - predicate storeStepLibrary(Node pred, Content c, Node succ) { - // Complex flow summary + predicate summaryStoreStep(Node pred, Content c, Node succ) { exists( - ControlFlow::Node callCfn, CallableFlowSource source, AdjustedAccessPath sourceAp, - CallableFlowSink sink, AdjustedAccessPath sinkAp, boolean preservesValue, - LibraryCodeNodeState predState, AdjustedAccessPath ap + SourceDeclarationCallable sdc, CallableFlowSource source, AccessPath sourceAp, + CallableFlowSink sink, AccessPath sinkAp, boolean preservesValue, + SummaryInternalNodeState predState, AccessPath predAp | - predState = TLibraryCodeNodeBeforeStoreState(ap) and - pred = TLibraryCodeNode(callCfn, source, sourceAp, sink, sinkAp, preservesValue, predState) and - c = ap.getHead() + predState = TSummaryInternalNodeBeforeStoreState(predAp) and + pred = TSummaryInternalNode(sdc, source, sourceAp, sink, sinkAp, preservesValue, predState) and + c = predAp.getHead() | // More stores needed - exists(LibraryCodeNodeState succState | + exists(SummaryInternalNodeState succState | succState = - TLibraryCodeNodeBeforeStoreState(any(AdjustedAccessPath succAp | succAp.getTail() = ap)) and - succ = TLibraryCodeNode(callCfn, source, sourceAp, sink, sinkAp, preservesValue, succState) + TSummaryInternalNodeBeforeStoreState(any(AccessPath succAp | succAp.getTail() = predAp)) and + succ = TSummaryInternalNode(sdc, source, sourceAp, sink, sinkAp, preservesValue, succState) ) or // Last store - ap = sinkAp and - exit(succ, callCfn, sink) - ) - or - // Value-preserving setter - setterLibrary(pred, c, succ, true) - } - - /** - * Holds if there is a read of `c` from `pred` to `succ`, which happens via - * library code. - */ - predicate getterLibrary(Node pred, Content c, Node succ, boolean preservesValue) { - exists(ControlFlow::Node callCfn, CallableFlowSource source, CallableFlowSink sink | - libraryFlowSummary(callCfn.getElement(), source, AdjustedAccessPath::singleton(c), sink, - AdjustedAccessPath::empty(), preservesValue) and - entry(pred, callCfn, source) and - exit(succ, callCfn, sink) + predAp = sinkAp and + succ = getSinkNode(sdc, sink) ) } @@ -1985,95 +1738,133 @@ module LibraryFlow { * Holds if data can flow from `pred` to `succ` via a read of content `c`, * using library code. */ - predicate readStepLibrary(Node pred, Content c, Node succ) { - // Complex flow summary + predicate summaryReadStep(Node pred, Content c, Node succ) { exists( - ControlFlow::Node callCfn, CallableFlowSource source, AdjustedAccessPath sourceAp, - CallableFlowSink sink, AdjustedAccessPath sinkAp, boolean preservesValue, - LibraryCodeNodeState succState, AdjustedAccessPath ap + SourceDeclarationCallable sdc, CallableFlowSource source, AccessPath sourceAp, + CallableFlowSink sink, AccessPath sinkAp, boolean preservesValue, + SummaryInternalNodeState succState, AccessPath succAp | - succState = TLibraryCodeNodeAfterReadState(ap) and - succ = TLibraryCodeNode(callCfn, source, sourceAp, sink, sinkAp, preservesValue, succState) and - c = ap.getHead() + succState = TSummaryInternalNodeAfterReadState(succAp) and + succ = TSummaryInternalNode(sdc, source, sourceAp, sink, sinkAp, preservesValue, succState) and + c = succAp.getHead() | // First read - ap = sourceAp and - entry(pred, callCfn, source) + succAp = sourceAp and + pred = getSourceNode(sdc, source) or // Subsequent reads - exists(LibraryCodeNodeState predState, AdjustedAccessPath predAp | - predState = TLibraryCodeNodeAfterReadState(predAp) and - predAp.getTail() = ap and - pred = TLibraryCodeNode(callCfn, source, sourceAp, sink, sinkAp, preservesValue, predState) + exists(SummaryInternalNodeState predState, AccessPath predAp | + predState = TSummaryInternalNodeAfterReadState(predAp) and + predAp.getTail() = succAp and + pred = TSummaryInternalNode(sdc, source, sourceAp, sink, sinkAp, preservesValue, predState) ) ) - or - // Value-preserving getter - getterLibrary(pred, c, succ, true) + } + + pragma[nomagic] + private SummaryParameterNode summaryArgParam(ArgumentNode arg, ReturnKind rk, OutNode out) { + exists(DataFlowCall call, int pos, SourceDeclarationCallable sdc | + arg.argumentOf(call, pos) and + call.getARuntimeTarget() = sdc and + result = TSummaryParameterNode(sdc, pos) and + call = out.getCall(rk) + ) + } + + /** + * Holds if `arg` flows to `out` using a simple flow summary, that is, a flow + * summary without delegates, reads, and stores. + */ + predicate summaryThroughStep(ArgumentNode arg, OutNode out, boolean preservesValue) { + exists(ReturnKind rk | + summaryLocalStep(summaryArgParam(arg, rk, out), TSummaryReturnNode(_, rk), preservesValue) + ) + } + + /** + * Holds if there is a (taint+)store of `arg` into content `c` of `out` using a + * flow summary. + */ + predicate summarySetterStep(ArgumentNode arg, Content c, OutNode out) { + exists(ReturnKind rk, Node mid | + summaryLocalStep(summaryArgParam(arg, rk, out), mid, _) and + summaryStoreStep(mid, c, TSummaryReturnNode(_, rk)) + ) + } + + /** + * Holds if there is a read(+taint) of `c` from `arg` to `out` using a + * flow summary. + */ + predicate summaryGetterStep(ArgumentNode arg, Content c, OutNode out) { + exists(ReturnKind rk, Node mid | + summaryReadStep(summaryArgParam(arg, rk, out), c, mid) and + summaryLocalStep(mid, TSummaryReturnNode(_, rk), _) + ) } /** * Holds if values stored inside content `c` are cleared at node `n`, as a result * of calling a library method. */ - predicate clearsContentLibrary(Node n, Content c) { + predicate summaryClearsContent(Node n, Content c) { exists(LibraryTypeDataFlow ltdf, CallableFlowSource source, Call call | ltdf.clearsContent(source, c, call.getTarget().getSourceDeclaration()) and n.asExpr() = source.getSource(call) ) } -} -/** Gets the type of content `c`. */ -pragma[noinline] -private Gvn::GvnType getContentType(Content c) { - exists(Type t | result = Gvn::getGlobalValueNumber(t) | - t = c.(FieldContent).getField().getType() - or - t = c.(PropertyContent).getProperty().getType() - or - c instanceof ElementContent and - t instanceof ObjectType // we don't know what the actual element type is - ) -} - -/** A data-flow node used to model flow through library code. */ -class LibraryCodeNode extends NodeImpl, TLibraryCodeNode { - private ControlFlow::Node callCfn; - private CallableFlowSource source; - private LibraryFlow::AdjustedAccessPath sourceAp; - private CallableFlowSink sink; - private LibraryFlow::AdjustedAccessPath sinkAp; - private boolean preservesValue; - private LibraryFlow::LibraryCodeNodeState state; - - LibraryCodeNode() { - this = TLibraryCodeNode(callCfn, source, sourceAp, sink, sinkAp, preservesValue, state) - } - - override Callable getEnclosingCallableImpl() { result = callCfn.getEnclosingCallable() } - - override Gvn::GvnType getDataFlowType() { - exists(LibraryFlow::AdjustedAccessPath ap | - state = LibraryFlow::TLibraryCodeNodeAfterReadState(ap) and - if sinkAp.length() = 0 and state.isLastReadState() and preservesValue = true - then result = Gvn::getGlobalValueNumber(sink.getSinkType(callCfn.getElement())) - else result = getContentType(ap.getHead()) + /** Gets the type of content `c`. */ + pragma[noinline] + private Gvn::GvnType getContentType(Content c) { + exists(Type t | result = Gvn::getGlobalValueNumber(t) | + t = c.(FieldContent).getField().getType() or - state = LibraryFlow::TLibraryCodeNodeBeforeStoreState(ap) and - if sourceAp.length() = 0 and state.isFirstStoreState() and preservesValue = true - then result = Gvn::getGlobalValueNumber(source.getSourceType(callCfn.getElement())) - else result = getContentType(ap.getHead()) + t = c.(PropertyContent).getProperty().getType() + or + c instanceof ElementContent and + t instanceof ObjectType // we don't know what the actual element type is ) } - override DotNet::Type getTypeImpl() { none() } + /** A data-flow node used to model flow summaries. */ + private class SummaryInternalNode extends SummaryNodeImpl, TSummaryInternalNode { + private SourceDeclarationCallable c; + private CallableFlowSource source; + private AccessPath sourceAp; + private CallableFlowSink sink; + private AccessPath sinkAp; + private boolean preservesValue; + private SummaryInternalNodeState state; - override ControlFlow::Node getControlFlowNodeImpl() { result = callCfn } + SummaryInternalNode() { + this = TSummaryInternalNode(c, source, sourceAp, sink, sinkAp, preservesValue, state) + } - override Location getLocationImpl() { result = callCfn.getLocation() } + override DataFlowCallable getEnclosingCallableImpl() { result = c } - override string toStringImpl() { result = "[library code: " + state + "] " + callCfn } + override Gvn::GvnType getDataFlowType() { + exists(AccessPath ap | + state = TSummaryInternalNodeAfterReadState(ap) and + if sinkAp.length() = 0 and state.isLastReadState() and preservesValue = true + then result = getSinkNode(c, sink).getDataFlowType() + else result = getContentType(ap.getHead()) + or + state = TSummaryInternalNodeBeforeStoreState(ap) and + if sourceAp.length() = 0 and state.isFirstStoreState() and preservesValue = true + then result = getSourceNode(c, source).getDataFlowType() + else result = getContentType(ap.getHead()) + ) + } + + override DotNet::Type getTypeImpl() { none() } + + override ControlFlow::Node getControlFlowNodeImpl() { none() } + + override Location getLocationImpl() { result = c.getLocation() } + + override string toStringImpl() { result = "[summary] " + state + " in " + c } + } } /** A field or a property. */ @@ -2325,7 +2116,7 @@ private module PostUpdateNodes { override MallocNode getPreUpdateNode() { result.getControlFlowNode() = cfn } - override DataFlowCallable getEnclosingCallableImpl() { result = cfn.getEnclosingCallable() } + override Callable getEnclosingCallableImpl() { result = cfn.getEnclosingCallable() } override DotNet::Type getTypeImpl() { result = oc.getType() } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll index 759921cf5be..bf012e53283 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll @@ -123,7 +123,8 @@ class ParameterNode extends Node { this.(SsaDefinitionNode).getDefinition() instanceof ImplicitCapturedParameterNodeImpl::SsaCapturedEntryDefinition or this = TInstanceParameterNode(_) or - this = TCilParameterNode(_) + this = TCilParameterNode(_) or + this = TSummaryParameterNode(_, _) } /** Gets the parameter corresponding to this node, if any. */ diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DelegateDataFlow.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DelegateDataFlow.qll index d031b345308..243c6b83ef5 100755 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DelegateDataFlow.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DelegateDataFlow.qll @@ -30,7 +30,7 @@ private class DelegateFlowSource extends DataFlow::ExprNode { } /** A sink of flow for a delegate expression. */ -abstract private class DelegateFlowSink extends DataFlow::ExprNode { +abstract private class DelegateFlowSink 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 @@ -92,7 +92,7 @@ abstract private class DelegateFlowSink extends DataFlow::ExprNode { } /** A delegate call expression. */ -library class DelegateCallExpr extends DelegateFlowSink { +class DelegateCallExpr extends DelegateFlowSink, DataFlow::ExprNode { DelegateCall dc; DelegateCallExpr() { this.getExpr() = dc.getDelegateExpr() } @@ -101,50 +101,15 @@ library class DelegateCallExpr extends DelegateFlowSink { DelegateCall getDelegateCall() { result = dc } } -/** A delegate expression that is passed as the argument to a library callable. */ -library class DelegateArgumentToLibraryCallable extends Expr { - DelegateType dt; - Call call; - - DelegateArgumentToLibraryCallable() { - exists(Callable callable, Parameter p | - this = call.getArgumentForParameter(p) and - callable = call.getTarget() and - callable.fromLibrary() and - dt = p.getType().(SystemLinqExpressions::DelegateExtType).getDelegateType() - ) - } - - /** Gets the call that this argument belongs to. */ - Call getCall() { result = call } - - /** Gets the index of this delegate argument in the call. */ - int getArgumentIndex() { this = this.getCall().getArgument(result) } - - /** Gets the delegate type of this argument. */ - DelegateType getDelegateType() { result = dt } - - /** - * 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 - * resolve the target, if any. Example: - */ - Callable getARuntimeTarget(CallContext context) { - exists(DelegateArgumentToLibraryCallableSink sink | sink.getExpr() = this | - result = sink.getARuntimeTarget(context) - ) - } -} - -/** A delegate expression that is passed as the argument to a library callable. */ -private class DelegateArgumentToLibraryCallableSink extends DelegateFlowSink { - DelegateArgumentToLibraryCallableSink() { - this.getExpr() instanceof DelegateArgumentToLibraryCallable +/** A parameter of delegate type belonging to a callable with a flow summary. */ +class SummaryDelegateParameterSink extends DelegateFlowSink, SummaryParameterNode { + SummaryDelegateParameterSink() { + this.getType() instanceof SystemLinqExpressions::DelegateExtType } } /** A delegate expression that is added to an event. */ -library class AddEventSource extends DelegateFlowSink { +class AddEventSource extends DelegateFlowSink, DataFlow::ExprNode { AddEventExpr ae; AddEventSource() { this.getExpr() = ae.getRValue() } @@ -192,7 +157,13 @@ private predicate flowsFrom( or // Local flow exists(DataFlow::Node mid | flowsFrom(sink, mid, isReturned, lastCall) | - DataFlow::localFlowStep(node, mid) or + LocalFlow::localFlowStepCommon(node, mid) + or + exists(Ssa::Definition def | + LocalFlow::localSsaFlowStep(def, node, mid) and + LocalFlow::usesInstanceField(def) + ) + or node.asExpr() = mid.asExpr().(DelegateCreation).getArgument() ) or @@ -205,7 +176,7 @@ private predicate flowsFrom( ) or // Flow into a callable (non-delegate call) - exists(ExplicitParameterNode mid, CallContext prevLastCall, NonDelegateCall call, Parameter p | + exists(ParameterNode mid, CallContext prevLastCall, NonDelegateCall call, Parameter p | flowsFrom(sink, mid, isReturned, prevLastCall) and isReturned = false and p = mid.getParameter() and @@ -215,8 +186,7 @@ private predicate flowsFrom( or // Flow into a callable (delegate call) exists( - ExplicitParameterNode mid, CallContext prevLastCall, DelegateCall call, Callable c, Parameter p, - int i + ParameterNode mid, CallContext prevLastCall, DelegateCall call, Callable c, Parameter p, int i | flowsFrom(sink, mid, isReturned, prevLastCall) and isReturned = false and diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/TaintTrackingPrivate.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/TaintTrackingPrivate.qll index 04af24087af..68284e965fa 100755 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/TaintTrackingPrivate.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/TaintTrackingPrivate.qll @@ -112,7 +112,7 @@ private predicate localTaintStepCommon(DataFlow::Node nodeFrom, DataFlow::Node n cached private module Cached { - private import LibraryFlow + private import Summaries /** * Holds if taint propagates from `nodeFrom` to `nodeTo` in exactly one local @@ -130,19 +130,19 @@ private module Cached { ( // Simple flow through library code is included in the exposed local // step relation, even though flow is technically inter-procedural - LibraryFlow::localStepLibrary(nodeFrom, nodeTo, false) + summaryThroughStep(nodeFrom, nodeTo, false) or // Taint collection by adding a tainted element exists(DataFlow::ElementContent c | storeStep(nodeFrom, c, nodeTo) or - setterLibrary(nodeFrom, c, nodeTo, false) + summarySetterStep(nodeFrom, c, nodeTo) ) or exists(DataFlow::Content c | readStep(nodeFrom, c, nodeTo) or - getterLibrary(nodeFrom, c, nodeTo, false) + summaryGetterStep(nodeFrom, c, nodeTo) | // Taint members c = any(TaintedMember m).(FieldOrProperty).getContent() @@ -169,7 +169,7 @@ private module Cached { // tracking configurations where the source is a collection readStep(nodeFrom, TElementContent(), nodeTo) or - LibraryFlow::localStepLibrary(nodeFrom, nodeTo, false) + summaryLocalStep(nodeFrom, nodeTo, false) or nodeTo = nodeFrom.(DataFlow::NonLocalJumpNode).getAJumpSuccessor(false) } diff --git a/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.expected b/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.expected index 63b053f20f7..89ab1d2a8d9 100644 --- a/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.expected @@ -51,54 +51,59 @@ edges | CollectionFlow.cs:109:14:109:17 | access to local variable list [[]] : A | CollectionFlow.cs:109:14:109:20 | access to indexer | | CollectionFlow.cs:110:22:110:25 | access to local variable list [[]] : A | CollectionFlow.cs:376:49:376:52 | list [[]] : A | | CollectionFlow.cs:111:24:111:27 | access to local variable list [[]] : A | CollectionFlow.cs:111:14:111:28 | call to method ListFirst | -| CollectionFlow.cs:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:127:9:127:12 | [post] access to local variable dict [[], Value] | +| CollectionFlow.cs:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:127:19:127:19 | access to local variable a : A | | CollectionFlow.cs:127:9:127:12 | [post] access to local variable dict [[], Value] | CollectionFlow.cs:128:14:128:17 | access to local variable dict [[], Value] | | CollectionFlow.cs:127:9:127:12 | [post] access to local variable dict [[], Value] | CollectionFlow.cs:129:23:129:26 | access to local variable dict [[], Value] | | CollectionFlow.cs:127:9:127:12 | [post] access to local variable dict [[], Value] | CollectionFlow.cs:130:28:130:31 | access to local variable dict [[], Value] | | CollectionFlow.cs:127:9:127:12 | [post] access to local variable dict [[], Value] | CollectionFlow.cs:131:29:131:32 | access to local variable dict [[], Value] | | CollectionFlow.cs:127:9:127:12 | [post] access to local variable dict [[], Value] | CollectionFlow.cs:132:30:132:33 | access to local variable dict [[], Value] | +| CollectionFlow.cs:127:19:127:19 | access to local variable a : A | CollectionFlow.cs:127:9:127:12 | [post] access to local variable dict [[], Value] | | CollectionFlow.cs:128:14:128:17 | access to local variable dict [[], Value] | CollectionFlow.cs:128:14:128:20 | access to indexer | | CollectionFlow.cs:129:23:129:26 | access to local variable dict [[], Value] | CollectionFlow.cs:378:61:378:64 | dict [[], Value] | | CollectionFlow.cs:130:28:130:31 | access to local variable dict [[], Value] | CollectionFlow.cs:130:14:130:32 | call to method DictIndexZero | | CollectionFlow.cs:131:29:131:32 | access to local variable dict [[], Value] | CollectionFlow.cs:131:14:131:33 | call to method DictFirstValue | | CollectionFlow.cs:132:30:132:33 | access to local variable dict [[], Value] | CollectionFlow.cs:132:14:132:34 | call to method DictValuesFirst | -| CollectionFlow.cs:148:17:148:23 | object creation of type A : A | CollectionFlow.cs:149:45:149:56 | { ..., ... } [[], Value] | +| CollectionFlow.cs:148:17:148:23 | object creation of type A : A | CollectionFlow.cs:149:52:149:52 | access to local variable a : A | | CollectionFlow.cs:149:45:149:56 | { ..., ... } [[], Value] | CollectionFlow.cs:150:14:150:17 | access to local variable dict [[], Value] | | CollectionFlow.cs:149:45:149:56 | { ..., ... } [[], Value] | CollectionFlow.cs:151:23:151:26 | access to local variable dict [[], Value] | | CollectionFlow.cs:149:45:149:56 | { ..., ... } [[], Value] | CollectionFlow.cs:152:28:152:31 | access to local variable dict [[], Value] | | CollectionFlow.cs:149:45:149:56 | { ..., ... } [[], Value] | CollectionFlow.cs:153:29:153:32 | access to local variable dict [[], Value] | | CollectionFlow.cs:149:45:149:56 | { ..., ... } [[], Value] | CollectionFlow.cs:154:30:154:33 | access to local variable dict [[], Value] | +| CollectionFlow.cs:149:52:149:52 | access to local variable a : A | CollectionFlow.cs:149:45:149:56 | { ..., ... } [[], Value] | | CollectionFlow.cs:150:14:150:17 | access to local variable dict [[], Value] | CollectionFlow.cs:150:14:150:20 | access to indexer | | CollectionFlow.cs:151:23:151:26 | access to local variable dict [[], Value] | CollectionFlow.cs:378:61:378:64 | dict [[], Value] | | CollectionFlow.cs:152:28:152:31 | access to local variable dict [[], Value] | CollectionFlow.cs:152:14:152:32 | call to method DictIndexZero | | CollectionFlow.cs:153:29:153:32 | access to local variable dict [[], Value] | CollectionFlow.cs:153:14:153:33 | call to method DictFirstValue | | CollectionFlow.cs:154:30:154:33 | access to local variable dict [[], Value] | CollectionFlow.cs:154:14:154:34 | call to method DictValuesFirst | -| CollectionFlow.cs:169:17:169:23 | object creation of type A : A | CollectionFlow.cs:170:45:170:55 | { ..., ... } [[], Value] | +| CollectionFlow.cs:169:17:169:23 | object creation of type A : A | CollectionFlow.cs:170:53:170:53 | access to local variable a : A | | CollectionFlow.cs:170:45:170:55 | { ..., ... } [[], Value] | CollectionFlow.cs:171:14:171:17 | access to local variable dict [[], Value] | | CollectionFlow.cs:170:45:170:55 | { ..., ... } [[], Value] | CollectionFlow.cs:172:23:172:26 | access to local variable dict [[], Value] | | CollectionFlow.cs:170:45:170:55 | { ..., ... } [[], Value] | CollectionFlow.cs:173:28:173:31 | access to local variable dict [[], Value] | | CollectionFlow.cs:170:45:170:55 | { ..., ... } [[], Value] | CollectionFlow.cs:174:29:174:32 | access to local variable dict [[], Value] | | CollectionFlow.cs:170:45:170:55 | { ..., ... } [[], Value] | CollectionFlow.cs:175:30:175:33 | access to local variable dict [[], Value] | +| CollectionFlow.cs:170:53:170:53 | access to local variable a : A | CollectionFlow.cs:170:45:170:55 | { ..., ... } [[], Value] | | CollectionFlow.cs:171:14:171:17 | access to local variable dict [[], Value] | CollectionFlow.cs:171:14:171:20 | access to indexer | | CollectionFlow.cs:172:23:172:26 | access to local variable dict [[], Value] | CollectionFlow.cs:378:61:378:64 | dict [[], Value] | | CollectionFlow.cs:173:28:173:31 | access to local variable dict [[], Value] | CollectionFlow.cs:173:14:173:32 | call to method DictIndexZero | | CollectionFlow.cs:174:29:174:32 | access to local variable dict [[], Value] | CollectionFlow.cs:174:14:174:33 | call to method DictFirstValue | | CollectionFlow.cs:175:30:175:33 | access to local variable dict [[], Value] | CollectionFlow.cs:175:14:175:34 | call to method DictValuesFirst | -| CollectionFlow.cs:191:17:191:23 | object creation of type A : A | CollectionFlow.cs:192:45:192:56 | { ..., ... } [[], Key] | +| CollectionFlow.cs:191:17:191:23 | object creation of type A : A | CollectionFlow.cs:192:49:192:49 | access to local variable a : A | | CollectionFlow.cs:192:45:192:56 | { ..., ... } [[], Key] | CollectionFlow.cs:193:14:193:17 | access to local variable dict [[], Key] | | CollectionFlow.cs:192:45:192:56 | { ..., ... } [[], Key] | CollectionFlow.cs:194:21:194:24 | access to local variable dict [[], Key] | | CollectionFlow.cs:192:45:192:56 | { ..., ... } [[], Key] | CollectionFlow.cs:195:28:195:31 | access to local variable dict [[], Key] | | CollectionFlow.cs:192:45:192:56 | { ..., ... } [[], Key] | CollectionFlow.cs:196:27:196:30 | access to local variable dict [[], Key] | +| CollectionFlow.cs:192:49:192:49 | access to local variable a : A | CollectionFlow.cs:192:45:192:56 | { ..., ... } [[], Key] | | CollectionFlow.cs:193:14:193:17 | access to local variable dict [[], Key] | CollectionFlow.cs:193:14:193:22 | access to property Keys [[]] : A | | CollectionFlow.cs:193:14:193:22 | access to property Keys [[]] : A | CollectionFlow.cs:193:14:193:30 | call to method First | | CollectionFlow.cs:194:21:194:24 | access to local variable dict [[], Key] | CollectionFlow.cs:380:59:380:62 | dict [[], Key] | | CollectionFlow.cs:195:28:195:31 | access to local variable dict [[], Key] | CollectionFlow.cs:195:14:195:32 | call to method DictKeysFirst | | CollectionFlow.cs:196:27:196:30 | access to local variable dict [[], Key] | CollectionFlow.cs:196:14:196:31 | call to method DictFirstKey | -| CollectionFlow.cs:210:17:210:23 | object creation of type A : A | CollectionFlow.cs:211:45:211:55 | { ..., ... } [[], Key] | +| CollectionFlow.cs:210:17:210:23 | object creation of type A : A | CollectionFlow.cs:211:48:211:48 | access to local variable a : A | | CollectionFlow.cs:211:45:211:55 | { ..., ... } [[], Key] | CollectionFlow.cs:212:14:212:17 | access to local variable dict [[], Key] | | CollectionFlow.cs:211:45:211:55 | { ..., ... } [[], Key] | CollectionFlow.cs:213:21:213:24 | access to local variable dict [[], Key] | | CollectionFlow.cs:211:45:211:55 | { ..., ... } [[], Key] | CollectionFlow.cs:214:28:214:31 | access to local variable dict [[], Key] | | CollectionFlow.cs:211:45:211:55 | { ..., ... } [[], Key] | CollectionFlow.cs:215:27:215:30 | access to local variable dict [[], Key] | +| CollectionFlow.cs:211:48:211:48 | access to local variable a : A | CollectionFlow.cs:211:45:211:55 | { ..., ... } [[], Key] | | CollectionFlow.cs:212:14:212:17 | access to local variable dict [[], Key] | CollectionFlow.cs:212:14:212:22 | access to property Keys [[]] : A | | CollectionFlow.cs:212:14:212:22 | access to property Keys [[]] : A | CollectionFlow.cs:212:14:212:30 | call to method First | | CollectionFlow.cs:213:21:213:24 | access to local variable dict [[], Key] | CollectionFlow.cs:380:59:380:62 | dict [[], Key] | @@ -155,6 +160,12 @@ edges | CollectionFlow.cs:374:52:374:53 | access to parameter ts [[]] : A | CollectionFlow.cs:374:52:374:56 | access to array element | | CollectionFlow.cs:374:52:374:53 | access to parameter ts [[]] : A | CollectionFlow.cs:374:52:374:56 | access to array element | | CollectionFlow.cs:376:49:376:52 | list [[]] : A | CollectionFlow.cs:376:63:376:66 | access to parameter list [[]] : A | +| CollectionFlow.cs:376:49:376:52 | list [[]] : A | CollectionFlow.cs:376:63:376:66 | access to parameter list [[]] : A | +| CollectionFlow.cs:376:49:376:52 | list [[]] : A | CollectionFlow.cs:376:63:376:66 | access to parameter list [[]] : A | +| CollectionFlow.cs:376:49:376:52 | list [[]] : A | CollectionFlow.cs:376:63:376:66 | access to parameter list [[]] : A | +| CollectionFlow.cs:376:63:376:66 | access to parameter list [[]] : A | CollectionFlow.cs:376:63:376:69 | access to indexer | +| CollectionFlow.cs:376:63:376:66 | access to parameter list [[]] : A | CollectionFlow.cs:376:63:376:69 | access to indexer | +| CollectionFlow.cs:376:63:376:66 | access to parameter list [[]] : A | CollectionFlow.cs:376:63:376:69 | access to indexer | | CollectionFlow.cs:376:63:376:66 | access to parameter list [[]] : A | CollectionFlow.cs:376:63:376:69 | access to indexer | | CollectionFlow.cs:378:61:378:64 | dict [[], Value] | CollectionFlow.cs:378:75:378:78 | access to parameter dict [[], Value] | | CollectionFlow.cs:378:75:378:78 | access to parameter dict [[], Value] | CollectionFlow.cs:378:75:378:81 | access to indexer | @@ -220,6 +231,7 @@ nodes | CollectionFlow.cs:111:24:111:27 | access to local variable list [[]] : A | semmle.label | access to local variable list [[]] : A | | CollectionFlow.cs:125:17:125:23 | object creation of type A : A | semmle.label | object creation of type A : A | | CollectionFlow.cs:127:9:127:12 | [post] access to local variable dict [[], Value] | semmle.label | [post] access to local variable dict [[], Value] | +| CollectionFlow.cs:127:19:127:19 | access to local variable a : A | semmle.label | access to local variable a : A | | CollectionFlow.cs:128:14:128:17 | access to local variable dict [[], Value] | semmle.label | access to local variable dict [[], Value] | | CollectionFlow.cs:128:14:128:20 | access to indexer | semmle.label | access to indexer | | CollectionFlow.cs:129:23:129:26 | access to local variable dict [[], Value] | semmle.label | access to local variable dict [[], Value] | @@ -231,6 +243,7 @@ nodes | CollectionFlow.cs:132:30:132:33 | access to local variable dict [[], Value] | semmle.label | access to local variable dict [[], Value] | | CollectionFlow.cs:148:17:148:23 | object creation of type A : A | semmle.label | object creation of type A : A | | CollectionFlow.cs:149:45:149:56 | { ..., ... } [[], Value] | semmle.label | { ..., ... } [[], Value] | +| CollectionFlow.cs:149:52:149:52 | access to local variable a : A | semmle.label | access to local variable a : A | | CollectionFlow.cs:150:14:150:17 | access to local variable dict [[], Value] | semmle.label | access to local variable dict [[], Value] | | CollectionFlow.cs:150:14:150:20 | access to indexer | semmle.label | access to indexer | | CollectionFlow.cs:151:23:151:26 | access to local variable dict [[], Value] | semmle.label | access to local variable dict [[], Value] | @@ -242,6 +255,7 @@ nodes | CollectionFlow.cs:154:30:154:33 | access to local variable dict [[], Value] | semmle.label | access to local variable dict [[], Value] | | CollectionFlow.cs:169:17:169:23 | object creation of type A : A | semmle.label | object creation of type A : A | | CollectionFlow.cs:170:45:170:55 | { ..., ... } [[], Value] | semmle.label | { ..., ... } [[], Value] | +| CollectionFlow.cs:170:53:170:53 | access to local variable a : A | semmle.label | access to local variable a : A | | CollectionFlow.cs:171:14:171:17 | access to local variable dict [[], Value] | semmle.label | access to local variable dict [[], Value] | | CollectionFlow.cs:171:14:171:20 | access to indexer | semmle.label | access to indexer | | CollectionFlow.cs:172:23:172:26 | access to local variable dict [[], Value] | semmle.label | access to local variable dict [[], Value] | @@ -253,6 +267,7 @@ nodes | CollectionFlow.cs:175:30:175:33 | access to local variable dict [[], Value] | semmle.label | access to local variable dict [[], Value] | | CollectionFlow.cs:191:17:191:23 | object creation of type A : A | semmle.label | object creation of type A : A | | CollectionFlow.cs:192:45:192:56 | { ..., ... } [[], Key] | semmle.label | { ..., ... } [[], Key] | +| CollectionFlow.cs:192:49:192:49 | access to local variable a : A | semmle.label | access to local variable a : A | | CollectionFlow.cs:193:14:193:17 | access to local variable dict [[], Key] | semmle.label | access to local variable dict [[], Key] | | CollectionFlow.cs:193:14:193:22 | access to property Keys [[]] : A | semmle.label | access to property Keys [[]] : A | | CollectionFlow.cs:193:14:193:30 | call to method First | semmle.label | call to method First | @@ -263,6 +278,7 @@ nodes | CollectionFlow.cs:196:27:196:30 | access to local variable dict [[], Key] | semmle.label | access to local variable dict [[], Key] | | CollectionFlow.cs:210:17:210:23 | object creation of type A : A | semmle.label | object creation of type A : A | | CollectionFlow.cs:211:45:211:55 | { ..., ... } [[], Key] | semmle.label | { ..., ... } [[], Key] | +| CollectionFlow.cs:211:48:211:48 | access to local variable a : A | semmle.label | access to local variable a : A | | CollectionFlow.cs:212:14:212:17 | access to local variable dict [[], Key] | semmle.label | access to local variable dict [[], Key] | | CollectionFlow.cs:212:14:212:22 | access to property Keys [[]] : A | semmle.label | access to property Keys [[]] : A | | CollectionFlow.cs:212:14:212:30 | call to method First | semmle.label | call to method First | @@ -327,6 +343,12 @@ nodes | CollectionFlow.cs:374:52:374:53 | access to parameter ts [[]] : A | semmle.label | access to parameter ts [[]] : A | | CollectionFlow.cs:374:52:374:56 | access to array element | semmle.label | access to array element | | CollectionFlow.cs:376:49:376:52 | list [[]] : A | semmle.label | list [[]] : A | +| CollectionFlow.cs:376:49:376:52 | list [[]] : A | semmle.label | list [[]] : A | +| CollectionFlow.cs:376:49:376:52 | list [[]] : A | semmle.label | list [[]] : A | +| CollectionFlow.cs:376:49:376:52 | list [[]] : A | semmle.label | list [[]] : A | +| CollectionFlow.cs:376:63:376:66 | access to parameter list [[]] : A | semmle.label | access to parameter list [[]] : A | +| CollectionFlow.cs:376:63:376:66 | access to parameter list [[]] : A | semmle.label | access to parameter list [[]] : A | +| CollectionFlow.cs:376:63:376:66 | access to parameter list [[]] : A | semmle.label | access to parameter list [[]] : A | | CollectionFlow.cs:376:63:376:66 | access to parameter list [[]] : A | semmle.label | access to parameter list [[]] : A | | CollectionFlow.cs:376:63:376:69 | access to indexer | semmle.label | access to indexer | | CollectionFlow.cs:378:61:378:64 | dict [[], Value] | semmle.label | dict [[], Value] | diff --git a/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.ql b/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.ql index 7c2c322f47f..7d02ffa7bcb 100644 --- a/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.ql +++ b/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.ql @@ -16,6 +16,8 @@ class Conf extends DataFlow::Configuration { mc.getAnArgument() = sink.asExpr() ) } + + override int fieldFlowBranchLimit() { result = 10 } } from DataFlow::PathNode source, DataFlow::PathNode sink, Conf conf diff --git a/csharp/ql/test/library-tests/dataflow/delegates/DelegateFlow.cs b/csharp/ql/test/library-tests/dataflow/delegates/DelegateFlow.cs index 7a50bcc057d..9479cca940d 100644 --- a/csharp/ql/test/library-tests/dataflow/delegates/DelegateFlow.cs +++ b/csharp/ql/test/library-tests/dataflow/delegates/DelegateFlow.cs @@ -99,5 +99,13 @@ class DelegateFlow M2(LocalFunction); } + public void M15() + { + Func f = () => 42; + new Lazy(f); + f = () => 43; + new Lazy(f); + } + public delegate void MyDelegate(); } diff --git a/csharp/ql/test/library-tests/dataflow/delegates/DelegateFlow.expected b/csharp/ql/test/library-tests/dataflow/delegates/DelegateFlow.expected index ecdd7f9e5f8..c8893ec9b0e 100644 --- a/csharp/ql/test/library-tests/dataflow/delegates/DelegateFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/delegates/DelegateFlow.expected @@ -1,3 +1,7 @@ +summaryDelegateCall +| file://:0:0:0:0 | [summary] valueFactory | DelegateFlow.cs:104:23:104:30 | (...) => ... | DelegateFlow.cs:105:23:105:23 | access to local variable f | +| file://:0:0:0:0 | [summary] 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 | | 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 | (...) => ... | diff --git a/csharp/ql/test/library-tests/dataflow/delegates/DelegateFlow.ql b/csharp/ql/test/library-tests/dataflow/delegates/DelegateFlow.ql index 2b0386491ea..c01feabc2f9 100644 --- a/csharp/ql/test/library-tests/dataflow/delegates/DelegateFlow.ql +++ b/csharp/ql/test/library-tests/dataflow/delegates/DelegateFlow.ql @@ -1,5 +1,22 @@ import csharp +import semmle.code.csharp.dataflow.internal.DataFlowPrivate +import semmle.code.csharp.dataflow.internal.DelegateDataFlow -from DelegateCall dc, Callable c, CallContext::CallContext cc -where c = dc.getARuntimeTarget(cc) -select dc, c, cc +private class NodeAdjusted extends TNode { + string toString() { result = this.(DataFlow::Node).toString() } + + Location getLocation() { + exists(Location l | + l = this.(DataFlow::Node).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) +} diff --git a/csharp/ql/test/library-tests/dataflow/global/Common.qll b/csharp/ql/test/library-tests/dataflow/global/Common.qll index 1ecaebd9f94..17d4b220876 100644 --- a/csharp/ql/test/library-tests/dataflow/global/Common.qll +++ b/csharp/ql/test/library-tests/dataflow/global/Common.qll @@ -10,10 +10,9 @@ class Config extends DataFlow::Configuration { } override predicate isSink(DataFlow::Node sink) { - sink.asExpr() instanceof Access and exists(MethodCall mc | mc.getTarget().getName() = "Check" and - mc.getAnArgument() = sink.asExpr().getParent*() + mc.getAnArgument() = sink.asExpr() ) } } diff --git a/csharp/ql/test/library-tests/dataflow/global/DataFlow.expected b/csharp/ql/test/library-tests/dataflow/global/DataFlow.expected index 6c3ddef4547..596f6f53274 100644 --- a/csharp/ql/test/library-tests/dataflow/global/DataFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/global/DataFlow.expected @@ -54,7 +54,7 @@ | 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 | -| Splitting.cs:21:28:21:32 | access to parameter value | +| Splitting.cs:21:21:21:33 | call to method Return | | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | | Splitting.cs:34:19:34:19 | access to local variable x | diff --git a/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.expected b/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.expected index 68fdc98c16b..c13ef765d93 100644 --- a/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.expected +++ b/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.expected @@ -228,7 +228,8 @@ edges | Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : String | Splitting.cs:11:19:11:19 | access to local variable x | | Splitting.cs:8:24:8:30 | [b (line 3): false] access to parameter tainted : String | Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return : 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): true] call to method Return : String | -| Splitting.cs:21:9:21:11 | value : String | Splitting.cs:21:28:21:32 | access to parameter value | +| Splitting.cs:21:9:21:11 | value : String | Splitting.cs:21:28:21:32 | access to parameter value : String | +| Splitting.cs:21:28:21:32 | access to parameter value : String | Splitting.cs:21:21:21:33 | call to method Return | | Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:30:17:30:23 | [b (line 24): false] access to parameter tainted : String | | Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted : String | | Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:31:19:31:25 | [b (line 24): false] access to parameter tainted : String | @@ -436,7 +437,8 @@ nodes | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | semmle.label | [b (line 3): true] access to local variable x | | Splitting.cs:11:19:11:19 | access to local variable x | semmle.label | access to local variable x | | Splitting.cs:21:9:21:11 | value : String | semmle.label | value : String | -| Splitting.cs:21:28:21:32 | access to parameter value | semmle.label | access to parameter value | +| Splitting.cs:21:21:21:33 | call to method Return | semmle.label | call to method Return | +| Splitting.cs:21:28:21:32 | access to parameter value : String | semmle.label | access to parameter value : String | | Splitting.cs:24:28:24:34 | tainted : String | semmle.label | tainted : String | | Splitting.cs:30:17:30:23 | [b (line 24): false] access to parameter tainted : String | semmle.label | [b (line 24): false] access to parameter tainted : String | | Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted : String | semmle.label | [b (line 24): true] access to parameter tainted : String | @@ -516,5 +518,5 @@ nodes | GlobalDataFlow.cs:287:15:287:24 | access to parameter sinkParam7 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:287:15:287:24 | access to parameter sinkParam7 | access to parameter sinkParam7 | | GlobalDataFlow.cs:314:15:314:24 | access to parameter sinkParam8 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:314:15:314:24 | access to parameter sinkParam8 | access to parameter sinkParam8 | | GlobalDataFlow.cs:320:15:320:24 | access to parameter sinkParam9 | GlobalDataFlow.cs:208:46:208:59 | "taint source" : String | GlobalDataFlow.cs:320:15:320:24 | access to parameter sinkParam9 | access to parameter sinkParam9 | -| Splitting.cs:21:28:21:32 | access to parameter value | Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:21:28:21:32 | access to parameter value | access to parameter value | | GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 | access to property SinkProperty0 | +| Splitting.cs:21:21:21:33 | call to method Return | Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:21:21:21:33 | call to method Return | call to method Return | diff --git a/csharp/ql/test/library-tests/dataflow/global/GetAnOutNode.expected b/csharp/ql/test/library-tests/dataflow/global/GetAnOutNode.expected index 730e18b8726..1acaa308256 100644 --- a/csharp/ql/test/library-tests/dataflow/global/GetAnOutNode.expected +++ b/csharp/ql/test/library-tests/dataflow/global/GetAnOutNode.expected @@ -1,25 +1,20 @@ | Capture.cs:33:9:33:40 | call to method Select | return | Capture.cs:33:9:33:40 | call to method Select | | Capture.cs:33:9:33:40 | call to method Select | yield return | Capture.cs:33:9:33:40 | call to method Select | | Capture.cs:33:9:33:50 | call to method ToArray | return | Capture.cs:33:9:33:50 | call to method ToArray | -| Capture.cs:33:30:33:39 | [implicit call] access to local variable captureIn3 | return | Capture.cs:33:30:33:39 | [output] access to local variable captureIn3 | | Capture.cs:71:9:71:21 | call to local function CaptureOut1 | captured sink30 | Capture.cs:71:9:71:21 | SSA call def(sink30) | | Capture.cs:83:9:83:21 | [transitive] call to local function CaptureOut2 | captured sink31 | Capture.cs:83:9:83:21 | SSA call def(sink31) | -| Capture.cs:92:9:92:41 | call to method Select | captured sink32 | Capture.cs:92:9:92:41 | SSA call def(sink32) | +| Capture.cs:92:9:92:41 | [transitive] call to method Select | captured sink32 | Capture.cs:92:9:92:41 | SSA call def(sink32) | | Capture.cs:92:9:92:41 | call to method Select | return | Capture.cs:92:9:92:41 | call to method Select | | Capture.cs:92:9:92:41 | call to method Select | yield return | Capture.cs:92:9:92:41 | call to method Select | | Capture.cs:92:9:92:51 | call to method ToArray | return | Capture.cs:92:9:92:51 | call to method ToArray | -| Capture.cs:92:30:92:40 | [implicit call] access to local variable captureOut3 | captured sink32 | Capture.cs:92:9:92:41 | SSA call def(sink32) | -| Capture.cs:92:30:92:40 | [implicit call] access to local variable captureOut3 | return | Capture.cs:92:30:92:40 | [output] access to local variable captureOut3 | | Capture.cs:121:9:121:35 | [transitive] call to local function CaptureOutMultipleLambdas | captured nonSink0 | Capture.cs:121:9:121:35 | SSA call def(nonSink0) | | Capture.cs:121:9:121:35 | [transitive] call to local function CaptureOutMultipleLambdas | captured sink40 | Capture.cs:121:9:121:35 | SSA call def(sink40) | | Capture.cs:132:9:132:25 | call to local function CaptureThrough1 | captured sink33 | Capture.cs:132:9:132:25 | SSA call def(sink33) | | Capture.cs:144:9:144:25 | [transitive] call to local function CaptureThrough2 | captured sink34 | Capture.cs:144:9:144:25 | SSA call def(sink34) | -| Capture.cs:153:9:153:45 | call to method Select | captured sink35 | Capture.cs:153:9:153:45 | SSA call def(sink35) | +| Capture.cs:153:9:153:45 | [transitive] call to method Select | captured sink35 | Capture.cs:153:9:153:45 | SSA call def(sink35) | | Capture.cs:153:9:153:45 | call to method Select | return | Capture.cs:153:9:153:45 | call to method Select | | Capture.cs:153:9:153:45 | call to method Select | yield return | Capture.cs:153:9:153:45 | call to method Select | | Capture.cs:153:9:153:55 | call to method ToArray | return | Capture.cs:153:9:153:55 | call to method ToArray | -| Capture.cs:153:30:153:44 | [implicit call] access to local variable captureThrough3 | captured sink35 | Capture.cs:153:9:153:45 | SSA call def(sink35) | -| Capture.cs:153:30:153:44 | [implicit call] access to local variable captureThrough3 | return | Capture.cs:153:30:153:44 | [output] access to local variable captureThrough3 | | Capture.cs:160:22:160:38 | call to local function CaptureThrough4 | return | Capture.cs:160:22:160:38 | call to local function CaptureThrough4 | | Capture.cs:168:9:168:32 | call to local function CaptureThrough5 | captured sink37 | Capture.cs:168:9:168:32 | SSA call def(sink37) | | Capture.cs:191:20:191:22 | call to local function M | return | Capture.cs:191:20:191:22 | call to local function M | @@ -32,6 +27,7 @@ | GlobalDataFlow.cs:32:9:32:29 | access to property NonSinkProperty1 | return | GlobalDataFlow.cs:32:9:32:29 | access to property NonSinkProperty1 | | GlobalDataFlow.cs:33:15:33:35 | access to property NonSinkProperty1 | return | GlobalDataFlow.cs:33:15:33:35 | access to property NonSinkProperty1 | | GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 | return | GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 | +| GlobalDataFlow.cs:37:26:37:58 | call to method GetMethod | qualifier | GlobalDataFlow.cs:37:26:37:41 | [post] typeof(...) | | GlobalDataFlow.cs:37:26:37:58 | call to method GetMethod | return | GlobalDataFlow.cs:37:26:37:58 | call to method GetMethod | | GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 | return | GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 | | GlobalDataFlow.cs:39:9:39:37 | call to method Invoke | return | GlobalDataFlow.cs:39:9:39:37 | call to method Invoke | @@ -41,11 +37,14 @@ | GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 | return | GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 | | GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 | return | GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 | | GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 | return | GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 | +| GlobalDataFlow.cs:65:9:65:18 | access to property InProperty | qualifier | GlobalDataFlow.cs:65:9:65:18 | [post] this access | | GlobalDataFlow.cs:65:9:65:18 | access to property InProperty | return | GlobalDataFlow.cs:65:9:65:18 | access to property InProperty | | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 | return | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 | +| GlobalDataFlow.cs:68:9:68:21 | access to property NonInProperty | qualifier | GlobalDataFlow.cs:68:9:68:21 | [post] this access | | GlobalDataFlow.cs:68:9:68:21 | access to property NonInProperty | return | GlobalDataFlow.cs:68:9:68:21 | access to property NonInProperty | | GlobalDataFlow.cs:71:21:71:46 | call to method Return | return | GlobalDataFlow.cs:71:21:71:46 | call to method Return | | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 | return | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 | +| GlobalDataFlow.cs:73:29:73:64 | call to method GetMethod | qualifier | GlobalDataFlow.cs:73:29:73:44 | [post] typeof(...) | | GlobalDataFlow.cs:73:29:73:64 | call to method GetMethod | return | GlobalDataFlow.cs:73:29:73:64 | call to method GetMethod | | GlobalDataFlow.cs:73:29:73:101 | call to method Invoke | return | GlobalDataFlow.cs:73:29:73:101 | call to method Invoke | | GlobalDataFlow.cs:76:9:76:46 | call to method ReturnOut | out | GlobalDataFlow.cs:76:30:76:34 | SSA def(sink2) | @@ -58,21 +57,14 @@ | GlobalDataFlow.cs:83:22:83:87 | call to method Select | return | GlobalDataFlow.cs:83:22:83:87 | call to method Select | | GlobalDataFlow.cs:83:22:83:87 | call to method Select | yield return | GlobalDataFlow.cs:83:22:83:87 | call to method Select | | GlobalDataFlow.cs:83:22:83:95 | call to method First | return | GlobalDataFlow.cs:83:22:83:95 | call to method First | -| GlobalDataFlow.cs:83:76:83:86 | [implicit call] delegate creation of type Func | return | GlobalDataFlow.cs:83:76:83:86 | [output] delegate creation of type Func | | GlobalDataFlow.cs:85:22:85:128 | call to method Zip | return | GlobalDataFlow.cs:85:22:85:128 | call to method Zip | | GlobalDataFlow.cs:85:22:85:128 | call to method Zip | yield return | GlobalDataFlow.cs:85:22:85:128 | call to method Zip | | GlobalDataFlow.cs:85:22:85:136 | call to method First | return | GlobalDataFlow.cs:85:22:85:136 | call to method First | -| GlobalDataFlow.cs:85:117:85:127 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:85:117:85:127 | [output] (...) => ... | | GlobalDataFlow.cs:87:22:87:128 | call to method Zip | return | GlobalDataFlow.cs:87:22:87:128 | call to method Zip | | GlobalDataFlow.cs:87:22:87:128 | call to method Zip | yield return | GlobalDataFlow.cs:87:22:87:128 | call to method Zip | | GlobalDataFlow.cs:87:22:87:136 | call to method First | return | GlobalDataFlow.cs:87:22:87:136 | call to method First | -| GlobalDataFlow.cs:87:117:87:127 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:87:117:87:127 | [output] (...) => ... | | GlobalDataFlow.cs:89:22:89:110 | call to method Aggregate | return | GlobalDataFlow.cs:89:22:89:110 | call to method Aggregate | -| GlobalDataFlow.cs:89:83:89:101 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:89:83:89:101 | [output] (...) => ... | -| GlobalDataFlow.cs:89:104:89:109 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:89:104:89:109 | [output] (...) => ... | | GlobalDataFlow.cs:91:22:91:110 | call to method Aggregate | return | GlobalDataFlow.cs:91:22:91:110 | call to method Aggregate | -| GlobalDataFlow.cs:91:83:91:101 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:91:83:91:101 | [output] (...) => ... | -| GlobalDataFlow.cs:91:104:91:109 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:91:104:91:109 | [output] (...) => ... | | GlobalDataFlow.cs:94:9:94:42 | call to method TryParse | out | GlobalDataFlow.cs:94:36:94:41 | SSA def(sink21) | | GlobalDataFlow.cs:94:9:94:42 | call to method TryParse | ref | GlobalDataFlow.cs:94:36:94:41 | SSA def(sink21) | | GlobalDataFlow.cs:94:9:94:42 | call to method TryParse | return | GlobalDataFlow.cs:94:9:94:42 | call to method TryParse | @@ -80,6 +72,7 @@ | GlobalDataFlow.cs:97:9:97:41 | call to method TryParse | ref | GlobalDataFlow.cs:97:35:97:40 | SSA def(sink22) | | GlobalDataFlow.cs:97:9:97:41 | call to method TryParse | return | GlobalDataFlow.cs:97:9:97:41 | call to method TryParse | | GlobalDataFlow.cs:101:24:101:33 | call to method Return | return | GlobalDataFlow.cs:101:24:101:33 | call to method Return | +| GlobalDataFlow.cs:103:28:103:63 | call to method GetMethod | qualifier | GlobalDataFlow.cs:103:28:103:43 | [post] typeof(...) | | GlobalDataFlow.cs:103:28:103:63 | call to method GetMethod | return | GlobalDataFlow.cs:103:28:103:63 | call to method GetMethod | | GlobalDataFlow.cs:103:28:103:103 | call to method Invoke | return | GlobalDataFlow.cs:103:28:103:103 | call to method Invoke | | GlobalDataFlow.cs:105:9:105:49 | call to method ReturnOut | out | GlobalDataFlow.cs:105:27:105:34 | SSA def(nonSink0) | @@ -95,24 +88,15 @@ | GlobalDataFlow.cs:115:20:115:82 | call to method Select | return | GlobalDataFlow.cs:115:20:115:82 | call to method Select | | GlobalDataFlow.cs:115:20:115:82 | call to method Select | yield return | GlobalDataFlow.cs:115:20:115:82 | call to method Select | | GlobalDataFlow.cs:115:20:115:90 | call to method First | return | GlobalDataFlow.cs:115:20:115:90 | call to method First | -| GlobalDataFlow.cs:115:76:115:81 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:115:76:115:81 | [output] (...) => ... | | GlobalDataFlow.cs:117:20:117:126 | call to method Zip | return | GlobalDataFlow.cs:117:20:117:126 | call to method Zip | | GlobalDataFlow.cs:117:20:117:126 | call to method Zip | yield return | GlobalDataFlow.cs:117:20:117:126 | call to method Zip | | GlobalDataFlow.cs:117:20:117:134 | call to method First | return | GlobalDataFlow.cs:117:20:117:134 | call to method First | -| GlobalDataFlow.cs:117:115:117:125 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:117:115:117:125 | [output] (...) => ... | | GlobalDataFlow.cs:119:20:119:126 | call to method Zip | return | GlobalDataFlow.cs:119:20:119:126 | call to method Zip | | GlobalDataFlow.cs:119:20:119:126 | call to method Zip | yield return | GlobalDataFlow.cs:119:20:119:126 | call to method Zip | | GlobalDataFlow.cs:119:20:119:134 | call to method First | return | GlobalDataFlow.cs:119:20:119:134 | call to method First | -| GlobalDataFlow.cs:119:115:119:125 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:119:115:119:125 | [output] (...) => ... | | GlobalDataFlow.cs:121:20:121:104 | call to method Aggregate | return | GlobalDataFlow.cs:121:20:121:104 | call to method Aggregate | -| GlobalDataFlow.cs:121:81:121:95 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:121:81:121:95 | [output] (...) => ... | -| GlobalDataFlow.cs:121:98:121:103 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:121:98:121:103 | [output] (...) => ... | | GlobalDataFlow.cs:123:20:123:109 | call to method Aggregate | return | GlobalDataFlow.cs:123:20:123:109 | call to method Aggregate | -| GlobalDataFlow.cs:123:81:123:99 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:123:81:123:99 | [output] (...) => ... | -| GlobalDataFlow.cs:123:102:123:108 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:123:102:123:108 | [output] (...) => ... | | GlobalDataFlow.cs:125:20:125:107 | call to method Aggregate | return | GlobalDataFlow.cs:125:20:125:107 | call to method Aggregate | -| GlobalDataFlow.cs:125:86:125:98 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:125:86:125:98 | [output] (...) => ... | -| GlobalDataFlow.cs:125:101:125:106 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:125:101:125:106 | [output] (...) => ... | | GlobalDataFlow.cs:128:9:128:46 | call to method TryParse | out | GlobalDataFlow.cs:128:38:128:45 | SSA def(nonSink2) | | GlobalDataFlow.cs:128:9:128:46 | call to method TryParse | ref | GlobalDataFlow.cs:128:38:128:45 | SSA def(nonSink2) | | GlobalDataFlow.cs:128:9:128:46 | call to method TryParse | return | GlobalDataFlow.cs:128:9:128:46 | call to method TryParse | @@ -125,20 +109,28 @@ | GlobalDataFlow.cs:144:21:144:44 | call to method ApplyFunc | return | GlobalDataFlow.cs:144:21:144:44 | call to method ApplyFunc | | GlobalDataFlow.cs:148:20:148:40 | call to method ApplyFunc | return | GlobalDataFlow.cs:148:20:148:40 | call to method ApplyFunc | | GlobalDataFlow.cs:150:20:150:44 | call to method ApplyFunc | return | GlobalDataFlow.cs:150:20:150:44 | call to method ApplyFunc | +| GlobalDataFlow.cs:154:21:154:25 | call to method Out | qualifier | GlobalDataFlow.cs:154:21:154:25 | [post] this access | | GlobalDataFlow.cs:154:21:154:25 | call to method Out | return | GlobalDataFlow.cs:154:21:154:25 | call to method Out | | GlobalDataFlow.cs:157:9:157:25 | call to method OutOut | out | GlobalDataFlow.cs:157:20:157:24 | SSA def(sink7) | +| GlobalDataFlow.cs:157:9:157:25 | call to method OutOut | qualifier | GlobalDataFlow.cs:157:9:157:25 | [post] this access | | GlobalDataFlow.cs:157:9:157:25 | call to method OutOut | ref | GlobalDataFlow.cs:157:20:157:24 | SSA def(sink7) | | GlobalDataFlow.cs:160:9:160:25 | call to method OutRef | out | GlobalDataFlow.cs:160:20:160:24 | SSA def(sink8) | +| GlobalDataFlow.cs:160:9:160:25 | call to method OutRef | qualifier | GlobalDataFlow.cs:160:9:160:25 | [post] this access | | GlobalDataFlow.cs:160:9:160:25 | call to method OutRef | ref | GlobalDataFlow.cs:160:20:160:24 | SSA def(sink8) | +| GlobalDataFlow.cs:162:22:162:31 | call to method OutYield | qualifier | GlobalDataFlow.cs:162:22:162:31 | [post] this access | | GlobalDataFlow.cs:162:22:162:31 | call to method OutYield | return | GlobalDataFlow.cs:162:22:162:31 | call to method OutYield | | GlobalDataFlow.cs:162:22:162:31 | call to method OutYield | yield return | GlobalDataFlow.cs:162:22:162:31 | call to method OutYield | | GlobalDataFlow.cs:162:22:162:39 | call to method First | return | GlobalDataFlow.cs:162:22:162:39 | call to method First | | GlobalDataFlow.cs:164:22:164:43 | call to method TaintedParam | return | GlobalDataFlow.cs:164:22:164:43 | call to method TaintedParam | +| GlobalDataFlow.cs:168:20:168:27 | call to method NonOut | qualifier | GlobalDataFlow.cs:168:20:168:27 | [post] this access | | GlobalDataFlow.cs:168:20:168:27 | call to method NonOut | return | GlobalDataFlow.cs:168:20:168:27 | call to method NonOut | | GlobalDataFlow.cs:170:9:170:31 | call to method NonOutOut | out | GlobalDataFlow.cs:170:23:170:30 | SSA def(nonSink0) | +| GlobalDataFlow.cs:170:9:170:31 | call to method NonOutOut | qualifier | GlobalDataFlow.cs:170:9:170:31 | [post] this access | | GlobalDataFlow.cs:170:9:170:31 | call to method NonOutOut | ref | GlobalDataFlow.cs:170:23:170:30 | SSA def(nonSink0) | | GlobalDataFlow.cs:172:9:172:31 | call to method NonOutRef | out | GlobalDataFlow.cs:172:23:172:30 | SSA def(nonSink0) | +| GlobalDataFlow.cs:172:9:172:31 | call to method NonOutRef | qualifier | GlobalDataFlow.cs:172:9:172:31 | [post] this access | | GlobalDataFlow.cs:172:9:172:31 | call to method NonOutRef | ref | GlobalDataFlow.cs:172:23:172:30 | SSA def(nonSink0) | +| GlobalDataFlow.cs:174:20:174:32 | call to method NonOutYield | qualifier | GlobalDataFlow.cs:174:20:174:32 | [post] this access | | GlobalDataFlow.cs:174:20:174:32 | call to method NonOutYield | return | GlobalDataFlow.cs:174:20:174:32 | call to method NonOutYield | | GlobalDataFlow.cs:174:20:174:32 | call to method NonOutYield | yield return | GlobalDataFlow.cs:174:20:174:32 | call to method NonOutYield | | GlobalDataFlow.cs:174:20:174:40 | call to method First | return | GlobalDataFlow.cs:174:20:174:40 | call to method First | @@ -146,12 +138,14 @@ | GlobalDataFlow.cs:181:21:181:26 | delegate call | return | GlobalDataFlow.cs:181:21:181:26 | delegate call | | GlobalDataFlow.cs:186:20:186:27 | delegate call | return | GlobalDataFlow.cs:186:20:186:27 | delegate call | | GlobalDataFlow.cs:190:22:190:42 | object creation of type Lazy | return | GlobalDataFlow.cs:190:22:190:42 | object creation of type Lazy | +| GlobalDataFlow.cs:190:22:190:48 | access to property Value | qualifier | GlobalDataFlow.cs:190:22:190:42 | [post] object creation of type Lazy | | GlobalDataFlow.cs:190:22:190:48 | access to property Value | return | GlobalDataFlow.cs:190:22:190:48 | access to property Value | -| GlobalDataFlow.cs:190:39:190:41 | [implicit call] delegate creation of type Func | return | GlobalDataFlow.cs:190:39:190:41 | [output] delegate creation of type Func | | GlobalDataFlow.cs:194:20:194:43 | object creation of type Lazy | return | GlobalDataFlow.cs:194:20:194:43 | object creation of type Lazy | +| GlobalDataFlow.cs:194:20:194:49 | access to property Value | qualifier | GlobalDataFlow.cs:194:20:194:43 | [post] object creation of type Lazy | | GlobalDataFlow.cs:194:20:194:49 | access to property Value | return | GlobalDataFlow.cs:194:20:194:49 | access to property Value | -| GlobalDataFlow.cs:194:37:194:42 | [implicit call] delegate creation of type Func | return | GlobalDataFlow.cs:194:37:194:42 | [output] delegate creation of type Func | +| GlobalDataFlow.cs:198:22:198:32 | access to property OutProperty | qualifier | GlobalDataFlow.cs:198:22:198:32 | [post] this access | | GlobalDataFlow.cs:198:22:198:32 | access to property OutProperty | return | GlobalDataFlow.cs:198:22:198:32 | access to property OutProperty | +| GlobalDataFlow.cs:202:20:202:33 | access to property NonOutProperty | qualifier | GlobalDataFlow.cs:202:20:202:33 | [post] this access | | GlobalDataFlow.cs:202:20:202:33 | access to property NonOutProperty | return | GlobalDataFlow.cs:202:20:202:33 | access to property NonOutProperty | | GlobalDataFlow.cs:208:38:208:75 | call to method AsQueryable | return | GlobalDataFlow.cs:208:38:208:75 | call to method AsQueryable | | GlobalDataFlow.cs:209:41:209:77 | call to method AsQueryable | return | GlobalDataFlow.cs:209:41:209:77 | call to method AsQueryable | @@ -159,52 +153,207 @@ | GlobalDataFlow.cs:213:22:213:39 | call to method Select | return | GlobalDataFlow.cs:213:22:213:39 | call to method Select | | GlobalDataFlow.cs:213:22:213:39 | call to method Select | yield return | GlobalDataFlow.cs:213:22:213:39 | call to method Select | | GlobalDataFlow.cs:213:22:213:47 | call to method First | return | GlobalDataFlow.cs:213:22:213:47 | call to method First | -| GlobalDataFlow.cs:213:37:213:38 | [implicit call] access to local variable f1 | return | GlobalDataFlow.cs:213:37:213:38 | [output] access to local variable f1 | | GlobalDataFlow.cs:215:22:215:39 | call to method Select | return | GlobalDataFlow.cs:215:22:215:39 | call to method Select | | GlobalDataFlow.cs:215:22:215:47 | call to method First | return | GlobalDataFlow.cs:215:22:215:47 | call to method First | -| GlobalDataFlow.cs:215:37:215:38 | [implicit call] access to local variable f2 | return | GlobalDataFlow.cs:215:37:215:38 | [output] access to local variable f2 | | GlobalDataFlow.cs:217:22:217:49 | call to method Select | return | GlobalDataFlow.cs:217:22:217:49 | call to method Select | | GlobalDataFlow.cs:217:22:217:49 | call to method Select | yield return | GlobalDataFlow.cs:217:22:217:49 | call to method Select | | GlobalDataFlow.cs:217:22:217:57 | call to method First | return | GlobalDataFlow.cs:217:22:217:57 | call to method First | -| GlobalDataFlow.cs:217:37:217:48 | [implicit call] delegate creation of type Func | return | GlobalDataFlow.cs:217:37:217:48 | [output] delegate creation of type Func | | GlobalDataFlow.cs:222:76:222:92 | call to method NonReturnCheck | return | GlobalDataFlow.cs:222:76:222:92 | call to method NonReturnCheck | | GlobalDataFlow.cs:223:23:223:43 | call to method Select | return | GlobalDataFlow.cs:223:23:223:43 | call to method Select | | GlobalDataFlow.cs:223:23:223:43 | call to method Select | yield return | GlobalDataFlow.cs:223:23:223:43 | call to method Select | | GlobalDataFlow.cs:223:23:223:51 | call to method First | return | GlobalDataFlow.cs:223:23:223:51 | call to method First | -| GlobalDataFlow.cs:223:41:223:42 | [implicit call] access to local variable f1 | return | GlobalDataFlow.cs:223:41:223:42 | [output] access to local variable f1 | | GlobalDataFlow.cs:225:19:225:39 | call to method Select | return | GlobalDataFlow.cs:225:19:225:39 | call to method Select | | GlobalDataFlow.cs:225:19:225:47 | call to method First | return | GlobalDataFlow.cs:225:19:225:47 | call to method First | -| GlobalDataFlow.cs:225:37:225:38 | [implicit call] access to local variable f2 | return | GlobalDataFlow.cs:225:37:225:38 | [output] access to local variable f2 | | GlobalDataFlow.cs:227:19:227:39 | call to method Select | return | GlobalDataFlow.cs:227:19:227:39 | call to method Select | | GlobalDataFlow.cs:227:19:227:39 | call to method Select | yield return | GlobalDataFlow.cs:227:19:227:39 | call to method Select | | GlobalDataFlow.cs:227:19:227:47 | call to method First | return | GlobalDataFlow.cs:227:19:227:47 | call to method First | -| GlobalDataFlow.cs:227:37:227:38 | [implicit call] access to local variable f3 | return | GlobalDataFlow.cs:227:37:227:38 | [output] access to local variable f3 | | GlobalDataFlow.cs:229:19:229:39 | call to method Select | return | GlobalDataFlow.cs:229:19:229:39 | call to method Select | | GlobalDataFlow.cs:229:19:229:47 | call to method First | return | GlobalDataFlow.cs:229:19:229:47 | call to method First | -| GlobalDataFlow.cs:229:37:229:38 | [implicit call] access to local variable f4 | return | GlobalDataFlow.cs:229:37:229:38 | [output] access to local variable f4 | | GlobalDataFlow.cs:231:19:231:49 | call to method Select | return | GlobalDataFlow.cs:231:19:231:49 | call to method Select | | GlobalDataFlow.cs:231:19:231:49 | call to method Select | yield return | GlobalDataFlow.cs:231:19:231:49 | call to method Select | | GlobalDataFlow.cs:231:19:231:57 | call to method First | return | GlobalDataFlow.cs:231:19:231:57 | call to method First | -| GlobalDataFlow.cs:231:37:231:48 | [implicit call] delegate creation of type Func | return | GlobalDataFlow.cs:231:37:231:48 | [output] delegate creation of type Func | | GlobalDataFlow.cs:238:20:238:49 | call to method Run | return | GlobalDataFlow.cs:238:20:238:49 | call to method Run | -| GlobalDataFlow.cs:238:29:238:48 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:238:29:238:48 | [output] (...) => ... | +| GlobalDataFlow.cs:239:22:239:32 | access to property Result | qualifier | GlobalDataFlow.cs:239:22:239:25 | [post] access to local variable task | | GlobalDataFlow.cs:239:22:239:32 | access to property Result | return | GlobalDataFlow.cs:239:22:239:32 | access to property Result | | GlobalDataFlow.cs:245:16:245:33 | call to method Run | return | GlobalDataFlow.cs:245:16:245:33 | call to method Run | -| GlobalDataFlow.cs:245:25:245:32 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:245:25:245:32 | [output] (...) => ... | +| GlobalDataFlow.cs:246:24:246:34 | access to property Result | qualifier | GlobalDataFlow.cs:246:24:246:27 | [post] access to local variable task | | GlobalDataFlow.cs:246:24:246:34 | access to property Result | return | GlobalDataFlow.cs:246:24:246:34 | access to property Result | | GlobalDataFlow.cs:297:17:297:38 | call to method ApplyFunc | return | GlobalDataFlow.cs:297:17:297:38 | call to method ApplyFunc | | GlobalDataFlow.cs:386:16:386:19 | delegate call | return | GlobalDataFlow.cs:386:16:386:19 | delegate call | -| GlobalDataFlow.cs:451:44:451:47 | delegate call | return | GlobalDataFlow.cs:451:44:451:47 | delegate call | +| GlobalDataFlow.cs:445:9:445:20 | call to method Append | qualifier | GlobalDataFlow.cs:445:9:445:10 | [post] access to parameter sb | +| GlobalDataFlow.cs:445:9:445:20 | call to method Append | return | GlobalDataFlow.cs:445:9:445:20 | call to method Append | +| GlobalDataFlow.cs:450:18:450:36 | object creation of type StringBuilder | return | GlobalDataFlow.cs:450:18:450:36 | object creation of type StringBuilder | +| GlobalDataFlow.cs:452:22:452:34 | call to method ToString | qualifier | GlobalDataFlow.cs:452:22:452:23 | [post] access to local variable sb | +| GlobalDataFlow.cs:452:22:452:34 | call to method ToString | return | GlobalDataFlow.cs:452:22:452:34 | call to method ToString | +| GlobalDataFlow.cs:455:9:455:18 | call to method Clear | qualifier | GlobalDataFlow.cs:455:9:455:10 | [post] access to local variable sb | +| GlobalDataFlow.cs:455:9:455:18 | call to method Clear | return | GlobalDataFlow.cs:455:9:455:18 | call to method Clear | +| GlobalDataFlow.cs:456:23:456:35 | call to method ToString | qualifier | GlobalDataFlow.cs:456:23:456:24 | [post] access to local variable sb | +| GlobalDataFlow.cs:456:23:456:35 | call to method ToString | return | GlobalDataFlow.cs:456:23:456:35 | call to method ToString | +| GlobalDataFlow.cs:462:22:462:65 | call to method Join | return | GlobalDataFlow.cs:462:22:462:65 | call to method Join | +| GlobalDataFlow.cs:465:23:465:65 | call to method Join | return | GlobalDataFlow.cs:465:23:465:65 | call to method Join | +| GlobalDataFlow.cs:477:44:477:47 | delegate call | return | GlobalDataFlow.cs:477:44:477: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 | | Splitting.cs:21:21:21:33 | call to method Return | return | Splitting.cs:21:21:21:33 | call to method Return | +| Splitting.cs:30:9:30:13 | [b (line 24): false] dynamic access to element | qualifier | Splitting.cs:30:9:30:9 | [post] [b (line 24): false] access to local variable d | | Splitting.cs:30:9:30:13 | [b (line 24): false] dynamic access to element | return | Splitting.cs:30:9:30:13 | [b (line 24): false] dynamic access to element | +| Splitting.cs:30:9:30:13 | [b (line 24): true] dynamic access to element | qualifier | Splitting.cs:30:9:30:9 | [post] [b (line 24): true] access to local variable d | | Splitting.cs:30:9:30:13 | [b (line 24): true] dynamic access to element | return | Splitting.cs:30:9:30:13 | [b (line 24): true] dynamic access to element | +| Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element | qualifier | Splitting.cs:31:17:31:17 | [post] [b (line 24): false] access to local variable d | | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element | return | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element | +| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element | qualifier | Splitting.cs:31:17:31:17 | [post] [b (line 24): true] access to local variable d | | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element | return | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element | | Splitting.cs:32:9:32:16 | [b (line 24): false] dynamic call to method Check | return | Splitting.cs:32:9:32:16 | [b (line 24): false] dynamic call to method Check | | Splitting.cs:32:9:32:16 | [b (line 24): true] dynamic call to method Check | return | Splitting.cs:32:9:32:16 | [b (line 24): true] dynamic call to method Check | | Splitting.cs:34:13:34:20 | dynamic call to method Check | return | Splitting.cs:34:13:34:20 | dynamic call to method Check | +| This.cs:12:9:12:20 | call to method M | qualifier | This.cs:12:9:12:12 | [post] this access | +| This.cs:13:9:13:15 | call to method M | qualifier | This.cs:13:9:13:15 | [post] this access | +| This.cs:15:9:15:21 | call to method M | qualifier | This.cs:15:9:15:12 | [post] this access | +| This.cs:16:9:16:16 | call to method M | qualifier | This.cs:16:9:16:16 | [post] this access | | This.cs:17:9:17:18 | object creation of type This | return | This.cs:17:9:17:18 | object creation of type This | +| This.cs:26:13:26:24 | call to method M | qualifier | This.cs:26:13:26:16 | [post] this access | +| This.cs:27:13:27:24 | call to method M | qualifier | This.cs:27:13:27:16 | [post] base access | | This.cs:28:13:28:21 | object creation of type Sub | return | This.cs:28:13:28:21 | object creation of type Sub | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of ContinueWith | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of ContinueWith] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Lazy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Lazy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Lazy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Lazy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Lazy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Lazy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Run | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Run] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Run | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Run] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Run | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Run] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Run | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Run] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of StartNew | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of StartNew] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Task | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Task] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Task | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Task] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Task | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Task] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Task | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Task] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Task | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Task] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Task | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Task] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Task | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Task] | +| file://:0:0:0:0 | [summary] delegate call, parameter 0 of Task | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 0 of Task] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of Aggregate | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of Aggregate] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of Aggregate | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of Aggregate] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAll | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAll] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of ContinueWhenAny | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of ContinueWhenAny] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of GroupBy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of GroupBy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of GroupBy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of GroupBy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of GroupBy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of GroupBy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of GroupBy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of GroupBy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of GroupBy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of GroupBy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of GroupBy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of GroupBy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of GroupBy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of GroupBy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of GroupBy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of GroupBy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of GroupBy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of GroupBy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of Select | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of Select] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of Select | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of Select] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of Select | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of Select] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of Select | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of Select] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of SelectMany | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of SelectMany] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of SelectMany | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of SelectMany] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of SelectMany | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of SelectMany] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of SelectMany | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of SelectMany] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of SelectMany | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of SelectMany] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of SelectMany | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of SelectMany] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of SelectMany | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of SelectMany] | +| file://:0:0:0:0 | [summary] delegate call, parameter 1 of SelectMany | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 1 of SelectMany] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of Aggregate | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of Aggregate] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of Aggregate | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of Aggregate] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of Aggregate | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of Aggregate] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of Aggregate | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of Aggregate] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of GroupBy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of GroupBy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of GroupBy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of GroupBy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of GroupBy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of GroupBy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of GroupBy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of GroupBy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of GroupBy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of GroupBy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of GroupBy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of GroupBy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of GroupBy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of GroupBy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of GroupBy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of GroupBy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of SelectMany | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of SelectMany] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of SelectMany | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of SelectMany] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of SelectMany | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of SelectMany] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of SelectMany | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of SelectMany] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of ToDictionary | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of ToDictionary] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of ToDictionary | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of ToDictionary] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of ToLookup | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of ToLookup] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of ToLookup | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of ToLookup] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of Zip | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of Zip] | +| file://:0:0:0:0 | [summary] delegate call, parameter 2 of Zip | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 2 of Zip] | +| file://:0:0:0:0 | [summary] delegate call, parameter 3 of Aggregate | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 3 of Aggregate] | +| file://:0:0:0:0 | [summary] delegate call, parameter 3 of Aggregate | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 3 of Aggregate] | +| file://:0:0:0:0 | [summary] delegate call, parameter 3 of GroupBy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 3 of GroupBy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 3 of GroupBy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 3 of GroupBy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 3 of GroupBy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 3 of GroupBy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 3 of GroupBy | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 3 of GroupBy] | +| file://:0:0:0:0 | [summary] delegate call, parameter 4 of GroupJoin | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 4 of GroupJoin] | +| file://:0:0:0:0 | [summary] delegate call, parameter 4 of GroupJoin | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 4 of GroupJoin] | +| file://:0:0:0:0 | [summary] delegate call, parameter 4 of GroupJoin | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 4 of GroupJoin] | +| file://:0:0:0:0 | [summary] delegate call, parameter 4 of GroupJoin | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 4 of GroupJoin] | +| file://:0:0:0:0 | [summary] delegate call, parameter 4 of Join | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 4 of Join] | +| file://:0:0:0:0 | [summary] delegate call, parameter 4 of Join | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 4 of Join] | +| file://:0:0:0:0 | [summary] delegate call, parameter 4 of Join | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 4 of Join] | +| file://:0:0:0:0 | [summary] delegate call, parameter 4 of Join | return | file://:0:0:0:0 | [summary] output from delegate call, parameter 4 of Join] | diff --git a/csharp/ql/test/library-tests/dataflow/global/GetAnOutNode.ql b/csharp/ql/test/library-tests/dataflow/global/GetAnOutNode.ql index e3cee19f724..a850a6af8d5 100644 --- a/csharp/ql/test/library-tests/dataflow/global/GetAnOutNode.ql +++ b/csharp/ql/test/library-tests/dataflow/global/GetAnOutNode.ql @@ -1,5 +1,29 @@ import csharp import semmle.code.csharp.dataflow.internal.DataFlowDispatch +import semmle.code.csharp.dataflow.internal.DataFlowPrivate -from DataFlowCall call, ReturnKind kind -select call, kind, getAnOutNode(call, kind) +private class DataFlowCallAdjusted extends TDataFlowCall { + 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 + ) + } +} + +private class NodeAdjusted extends TNode { + string toString() { result = this.(DataFlow::Node).toString() } + + Location getLocation() { + exists(Location l | + l = this.(DataFlow::Node).getLocation() and + if l instanceof SourceLocation then result = l else result instanceof EmptyLocation + ) + } +} + +from DataFlowCallAdjusted call, NodeAdjusted n, ReturnKind kind +where n = getAnOutNode(call, kind) +select call, kind, n diff --git a/csharp/ql/test/library-tests/dataflow/global/GlobalDataFlow.cs b/csharp/ql/test/library-tests/dataflow/global/GlobalDataFlow.cs index f62f0915a21..35c38fb809b 100644 --- a/csharp/ql/test/library-tests/dataflow/global/GlobalDataFlow.cs +++ b/csharp/ql/test/library-tests/dataflow/global/GlobalDataFlow.cs @@ -439,6 +439,32 @@ public class DataFlow { get { return ""; } } + + static void AppendToStringBuilder(StringBuilder sb, string s) + { + sb.Append(s); + } + + void TestStringBuilderFlow() + { + var sb = new StringBuilder(); + AppendToStringBuilder(sb, "taint source"); + var sink43 = sb.ToString(); + Check(sink43); + + sb.Clear(); + var nonSink = sb.ToString(); + Check(nonSink); + } + + void TestStringFlow() + { + var sink44 = string.Join(",", "whatever", "taint source"); + Check(sink44); + + var nonSink = string.Join(",", "whatever", "not tainted"); + Check(nonSink); + } } static class IEnumerableExtensions diff --git a/csharp/ql/test/library-tests/dataflow/global/TaintTracking.expected b/csharp/ql/test/library-tests/dataflow/global/TaintTracking.expected index fbd507ea781..aee973d855b 100644 --- a/csharp/ql/test/library-tests/dataflow/global/TaintTracking.expected +++ b/csharp/ql/test/library-tests/dataflow/global/TaintTracking.expected @@ -55,10 +55,12 @@ | GlobalDataFlow.cs:326:15:326:25 | access to parameter sinkParam11 | | GlobalDataFlow.cs:401:15:401:20 | access to local variable sink11 | | GlobalDataFlow.cs:424:41:424:46 | access to local variable sink20 | +| GlobalDataFlow.cs:453:15:453:20 | access to local variable sink43 | +| GlobalDataFlow.cs:463:15:463:20 | access to local variable sink44 | | 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 | -| Splitting.cs:21:28:21:32 | access to parameter value | +| Splitting.cs:21:21:21:33 | call to method Return | | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | | Splitting.cs:34:19:34:19 | access to local variable x | diff --git a/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.expected b/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.expected index 5f4a898112b..a0ac519a6c6 100644 --- a/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.expected +++ b/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.expected @@ -129,9 +129,7 @@ edges | GlobalDataFlow.cs:83:22:83:95 | call to method First : String | GlobalDataFlow.cs:84:15:84:20 | access to local variable sink14 | | GlobalDataFlow.cs:83:22:83:95 | call to method First : String | GlobalDataFlow.cs:85:59:85:64 | access to local variable sink14 : String | | GlobalDataFlow.cs:83:22:83:95 | call to method First : String | GlobalDataFlow.cs:89:59:89:64 | access to local variable sink14 : String | -| GlobalDataFlow.cs:83:22:83:95 | call to method First : String | GlobalDataFlow.cs:92:15:92:20 | access to local variable sink18 | -| GlobalDataFlow.cs:83:22:83:95 | call to method First : String | GlobalDataFlow.cs:95:15:95:20 | access to local variable sink21 | -| GlobalDataFlow.cs:83:22:83:95 | call to method First : String | GlobalDataFlow.cs:98:15:98:20 | access to local variable sink22 | +| GlobalDataFlow.cs:83:22:83:95 | call to method First : String | GlobalDataFlow.cs:91:75:91:80 | access to local variable sink14 : String | | GlobalDataFlow.cs:83:23:83:66 | (...) ... [[]] : String | GlobalDataFlow.cs:83:22:83:87 | call to method Select [[]] : String | | GlobalDataFlow.cs:83:23:83:66 | (...) ... [[]] : String | GlobalDataFlow.cs:312:31:312:40 | sinkParam8 : String | | GlobalDataFlow.cs:83:57:83:66 | { ..., ... } [[]] : String | GlobalDataFlow.cs:83:23:83:66 | (...) ... [[]] : String | @@ -147,9 +145,18 @@ edges | GlobalDataFlow.cs:87:70:87:113 | (...) ... [[]] : String | GlobalDataFlow.cs:87:22:87:128 | call to method Zip [[]] : String | | GlobalDataFlow.cs:87:104:87:113 | { ..., ... } [[]] : String | GlobalDataFlow.cs:87:70:87:113 | (...) ... [[]] : String | | GlobalDataFlow.cs:87:106:87:111 | access to local variable sink15 : String | GlobalDataFlow.cs:87:104:87:113 | { ..., ... } [[]] : String | -| GlobalDataFlow.cs:89:23:89:66 | (...) ... [[]] : String | GlobalDataFlow.cs:90:15:90:20 | access to local variable sink17 | +| GlobalDataFlow.cs:89:22:89:110 | call to method Aggregate : String | GlobalDataFlow.cs:90:15:90:20 | access to local variable sink17 | +| GlobalDataFlow.cs:89:23:89:66 | (...) ... [[]] : String | GlobalDataFlow.cs:89:22:89:110 | call to method Aggregate : String | | GlobalDataFlow.cs:89:57:89:66 | { ..., ... } [[]] : String | GlobalDataFlow.cs:89:23:89:66 | (...) ... [[]] : String | | GlobalDataFlow.cs:89:59:89:64 | access to local variable sink14 : String | GlobalDataFlow.cs:89:57:89:66 | { ..., ... } [[]] : String | +| GlobalDataFlow.cs:91:22:91:110 | call to method Aggregate : String | GlobalDataFlow.cs:92:15:92:20 | access to local variable sink18 | +| GlobalDataFlow.cs:91:22:91:110 | call to method Aggregate : String | GlobalDataFlow.cs:94:24:94:29 | access to local variable sink18 : String | +| GlobalDataFlow.cs:91:22:91:110 | call to method Aggregate : String | GlobalDataFlow.cs:97:23:97:28 | access to local variable sink18 : String | +| GlobalDataFlow.cs:91:75:91:80 | access to local variable sink14 : String | GlobalDataFlow.cs:91:22:91:110 | call to method Aggregate : String | +| GlobalDataFlow.cs:94:24:94:29 | access to local variable sink18 : String | GlobalDataFlow.cs:94:36:94:41 | SSA def(sink21) : Int32 | +| GlobalDataFlow.cs:94:36:94:41 | SSA def(sink21) : Int32 | GlobalDataFlow.cs:95:15:95:20 | access to local variable sink21 | +| GlobalDataFlow.cs:97:23:97:28 | access to local variable sink18 : String | GlobalDataFlow.cs:97:35:97:40 | SSA def(sink22) : Boolean | +| GlobalDataFlow.cs:97:35:97:40 | SSA def(sink22) : Boolean | GlobalDataFlow.cs:98:15:98:20 | access to local variable sink22 | | GlobalDataFlow.cs:136:21:136:34 | delegate call : String | GlobalDataFlow.cs:137:15:137:19 | access to local variable sink4 | | GlobalDataFlow.cs:136:21:136:34 | delegate call : String | GlobalDataFlow.cs:144:39:144:43 | access to local variable sink4 : String | | GlobalDataFlow.cs:136:29:136:33 | access to local variable sink3 : String | GlobalDataFlow.cs:136:21:136:34 | delegate call : String | @@ -228,6 +235,12 @@ edges | GlobalDataFlow.cs:402:16:402:21 | access to local variable sink11 : String | GlobalDataFlow.cs:164:22:164:43 | call to method TaintedParam : String | | GlobalDataFlow.cs:424:9:424:11 | value : String | GlobalDataFlow.cs:424:41:424:46 | access to local variable sink20 | | GlobalDataFlow.cs:435:22:435:35 | "taint source" : String | GlobalDataFlow.cs:198:22:198:32 | access to property OutProperty : String | +| GlobalDataFlow.cs:451:31:451:32 | [post] access to local variable sb [[]] : String | GlobalDataFlow.cs:452:22:452:23 | access to local variable sb [[]] : String | +| GlobalDataFlow.cs:451:35:451:48 | "taint source" : String | GlobalDataFlow.cs:451:31:451:32 | [post] access to local variable sb [[]] : String | +| GlobalDataFlow.cs:452:22:452:23 | access to local variable sb [[]] : String | GlobalDataFlow.cs:452:22:452:34 | call to method ToString : String | +| GlobalDataFlow.cs:452:22:452:34 | call to method ToString : String | GlobalDataFlow.cs:453:15:453:20 | access to local variable sink43 | +| GlobalDataFlow.cs:462:22:462:65 | call to method Join : String | GlobalDataFlow.cs:463:15:463:20 | access to local variable sink44 | +| GlobalDataFlow.cs:462:51:462:64 | "taint source" : String | GlobalDataFlow.cs:462:22:462:65 | call to method Join : 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 | @@ -235,7 +248,8 @@ edges | Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : String | Splitting.cs:11:19:11:19 | access to local variable x | | Splitting.cs:8:24:8:30 | [b (line 3): false] access to parameter tainted : String | Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return : 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): true] call to method Return : String | -| Splitting.cs:21:9:21:11 | value : String | Splitting.cs:21:28:21:32 | access to parameter value | +| Splitting.cs:21:9:21:11 | value : String | Splitting.cs:21:28:21:32 | access to parameter value : String | +| Splitting.cs:21:28:21:32 | access to parameter value : String | Splitting.cs:21:21:21:33 | call to method Return | | Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:30:17:30:23 | [b (line 24): false] access to parameter tainted : String | | Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted : String | | Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:31:19:31:25 | [b (line 24): false] access to parameter tainted : String | @@ -338,12 +352,19 @@ nodes | GlobalDataFlow.cs:87:104:87:113 | { ..., ... } [[]] : String | semmle.label | { ..., ... } [[]] : String | | GlobalDataFlow.cs:87:106:87:111 | access to local variable sink15 : String | semmle.label | access to local variable sink15 : String | | GlobalDataFlow.cs:88:15:88:20 | access to local variable sink16 | semmle.label | access to local variable sink16 | +| GlobalDataFlow.cs:89:22:89:110 | call to method Aggregate : String | semmle.label | call to method Aggregate : String | | GlobalDataFlow.cs:89:23:89:66 | (...) ... [[]] : String | semmle.label | (...) ... [[]] : String | | GlobalDataFlow.cs:89:57:89:66 | { ..., ... } [[]] : String | semmle.label | { ..., ... } [[]] : String | | GlobalDataFlow.cs:89:59:89:64 | access to local variable sink14 : String | semmle.label | access to local variable sink14 : String | | GlobalDataFlow.cs:90:15:90:20 | access to local variable sink17 | semmle.label | access to local variable sink17 | +| GlobalDataFlow.cs:91:22:91:110 | call to method Aggregate : String | semmle.label | call to method Aggregate : String | +| GlobalDataFlow.cs:91:75:91:80 | access to local variable sink14 : String | semmle.label | access to local variable sink14 : String | | GlobalDataFlow.cs:92:15:92:20 | access to local variable sink18 | semmle.label | access to local variable sink18 | +| GlobalDataFlow.cs:94:24:94:29 | access to local variable sink18 : String | semmle.label | access to local variable sink18 : String | +| GlobalDataFlow.cs:94:36:94:41 | SSA def(sink21) : Int32 | semmle.label | SSA def(sink21) : Int32 | | GlobalDataFlow.cs:95:15:95:20 | access to local variable sink21 | semmle.label | access to local variable sink21 | +| GlobalDataFlow.cs:97:23:97:28 | access to local variable sink18 : String | semmle.label | access to local variable sink18 : String | +| GlobalDataFlow.cs:97:35:97:40 | SSA def(sink22) : Boolean | semmle.label | SSA def(sink22) : Boolean | | GlobalDataFlow.cs:98:15:98:20 | access to local variable sink22 | semmle.label | access to local variable sink22 | | GlobalDataFlow.cs:136:21:136:34 | delegate call : String | semmle.label | delegate call : String | | GlobalDataFlow.cs:136:29:136:33 | access to local variable sink3 : String | semmle.label | access to local variable sink3 : String | @@ -441,6 +462,14 @@ nodes | GlobalDataFlow.cs:424:9:424:11 | value : String | semmle.label | value : String | | GlobalDataFlow.cs:424:41:424:46 | access to local variable sink20 | semmle.label | access to local variable sink20 | | GlobalDataFlow.cs:435:22:435:35 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:451:31:451:32 | [post] access to local variable sb [[]] : String | semmle.label | [post] access to local variable sb [[]] : String | +| GlobalDataFlow.cs:451:35:451:48 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:452:22:452:23 | access to local variable sb [[]] : String | semmle.label | access to local variable sb [[]] : String | +| GlobalDataFlow.cs:452:22:452:34 | call to method ToString : String | semmle.label | call to method ToString : String | +| GlobalDataFlow.cs:453:15:453:20 | access to local variable sink43 | semmle.label | access to local variable sink43 | +| GlobalDataFlow.cs:462:22:462:65 | call to method Join : String | semmle.label | call to method Join : String | +| GlobalDataFlow.cs:462:51:462:64 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:463:15:463:20 | access to local variable sink44 | semmle.label | access to local variable sink44 | | 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 | @@ -450,7 +479,8 @@ nodes | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | semmle.label | [b (line 3): true] access to local variable x | | Splitting.cs:11:19:11:19 | access to local variable x | semmle.label | access to local variable x | | Splitting.cs:21:9:21:11 | value : String | semmle.label | value : String | -| Splitting.cs:21:28:21:32 | access to parameter value | semmle.label | access to parameter value | +| Splitting.cs:21:21:21:33 | call to method Return | semmle.label | call to method Return | +| Splitting.cs:21:28:21:32 | access to parameter value : String | semmle.label | access to parameter value : String | | Splitting.cs:24:28:24:34 | tainted : String | semmle.label | tainted : String | | Splitting.cs:30:17:30:23 | [b (line 24): false] access to parameter tainted : String | semmle.label | [b (line 24): false] access to parameter tainted : String | | Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted : String | semmle.label | [b (line 24): true] access to parameter tainted : String | @@ -525,10 +555,12 @@ nodes | GlobalDataFlow.cs:326:15:326:25 | access to parameter sinkParam11 | GlobalDataFlow.cs:208:46:208:59 | "taint source" : String | GlobalDataFlow.cs:326:15:326:25 | access to parameter sinkParam11 | access to parameter sinkParam11 | | GlobalDataFlow.cs:401:15:401:20 | access to local variable sink11 | GlobalDataFlow.cs:398:39:398:45 | tainted : String | GlobalDataFlow.cs:401:15:401:20 | access to local variable sink11 | access to local variable sink11 | | GlobalDataFlow.cs:424:41:424:46 | access to local variable sink20 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:424:41:424:46 | access to local variable sink20 | access to local variable sink20 | +| 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 | | 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 | -| Splitting.cs:21:28:21:32 | access to parameter value | Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:21:28:21:32 | access to parameter value | access to parameter value | +| Splitting.cs:21:21:21:33 | call to method Return | Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:21:21:21:33 | call to method Return | call to method Return | | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | [b (line 24): false] access to local variable x | | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | [b (line 24): true] 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 | diff --git a/csharp/ql/test/library-tests/dataflow/ssa/SsaCapturedVariableDef.expected b/csharp/ql/test/library-tests/dataflow/ssa/SsaCapturedVariableDef.expected index e1b4a0b52b2..baa9311a09b 100644 --- a/csharp/ql/test/library-tests/dataflow/ssa/SsaCapturedVariableDef.expected +++ b/csharp/ql/test/library-tests/dataflow/ssa/SsaCapturedVariableDef.expected @@ -4,11 +4,11 @@ | in | Capture.cs:8:13:8:13 | x | Capture.cs:15:13:15:17 | SSA def(x) | Capture.cs:19:24:23:13 | SSA capture def(x) | Capture.cs:25:13:25:15 | delegate call | false | | in | Capture.cs:8:13:8:13 | x | Capture.cs:43:9:43:13 | SSA def(x) | Capture.cs:19:24:23:13 | SSA capture def(x) | Capture.cs:44:9:44:12 | call to method M | true | | in | Capture.cs:17:17:17:17 | y | Capture.cs:17:17:17:21 | SSA def(y) | Capture.cs:19:24:23:13 | SSA capture def(y) | Capture.cs:25:13:25:15 | delegate call | false | -| in | Capture.cs:59:13:59:13 | i | Capture.cs:59:13:59:17 | SSA def(i) | Capture.cs:60:31:60:38 | SSA capture def(i) | Capture.cs:61:9:61:25 | call to method Select | false | -| in | Capture.cs:67:13:67:13 | c | Capture.cs:67:13:67:19 | SSA def(c) | Capture.cs:68:32:68:49 | SSA capture def(c) | Capture.cs:68:18:68:50 | call to method Where | false | -| in | Capture.cs:67:13:67:13 | c | Capture.cs:67:13:67:19 | SSA def(c) | Capture.cs:69:9:69:62 | SSA capture def(c) | Capture.cs:70:9:70:25 | call to method Select | false | -| in | Capture.cs:75:13:75:13 | i | Capture.cs:75:13:75:17 | SSA def(i) | Capture.cs:76:67:76:81 | SSA capture def(i) | Capture.cs:77:9:77:25 | call to method Select | false | -| in | Capture.cs:85:13:85:13 | b | Capture.cs:85:13:85:20 | SSA def(b) | Capture.cs:86:68:86:73 | SSA capture def(b) | Capture.cs:87:9:87:24 | call to method Where | false | +| in | Capture.cs:59:13:59:13 | i | Capture.cs:59:13:59:17 | SSA def(i) | Capture.cs:60:31:60:38 | SSA capture def(i) | Capture.cs:61:9:61:25 | call to method Select | true | +| in | Capture.cs:67:13:67:13 | c | Capture.cs:67:13:67:19 | SSA def(c) | Capture.cs:68:32:68:49 | SSA capture def(c) | Capture.cs:68:18:68:50 | call to method Where | true | +| in | Capture.cs:67:13:67:13 | c | Capture.cs:67:13:67:19 | SSA def(c) | Capture.cs:69:9:69:62 | SSA capture def(c) | Capture.cs:70:9:70:25 | call to method Select | true | +| in | Capture.cs:75:13:75:13 | i | Capture.cs:75:13:75:17 | SSA def(i) | Capture.cs:76:67:76:81 | SSA capture def(i) | Capture.cs:77:9:77:25 | call to method Select | true | +| in | Capture.cs:85:13:85:13 | b | Capture.cs:85:13:85:20 | SSA def(b) | Capture.cs:86:68:86:73 | SSA capture def(b) | Capture.cs:87:9:87:24 | call to method Where | true | | in | Capture.cs:94:13:94:13 | y | Capture.cs:94:13:94:18 | SSA def(y) | Capture.cs:96:12:100:9 | SSA capture def(y) | Capture.cs:96:9:100:10 | call to local function fn | true | | in | Capture.cs:94:13:94:13 | y | Capture.cs:94:13:94:18 | SSA def(y) | Capture.cs:96:12:100:9 | SSA capture def(y) | Capture.cs:103:9:107:10 | call to local function fn | true | | in | Capture.cs:114:13:114:13 | a | Capture.cs:114:13:114:18 | SSA def(a) | Capture.cs:115:9:119:9 | SSA capture def(a) | Capture.cs:120:9:120:12 | call to local function M1 | false | @@ -16,23 +16,23 @@ | in | Capture.cs:182:17:182:17 | i | Capture.cs:188:13:188:17 | SSA def(i) | Capture.cs:183:13:186:13 | SSA capture def(i) | Capture.cs:189:13:189:17 | call to local function M11 | false | | in | Capture.cs:197:17:197:17 | i | Capture.cs:197:17:197:21 | SSA def(i) | Capture.cs:198:33:198:44 | SSA capture def(i) | Capture.cs:200:13:200:19 | delegate call | false | | in | Capture.cs:197:17:197:17 | i | Capture.cs:197:17:197:21 | SSA def(i) | Capture.cs:203:34:203:45 | SSA capture def(i) | Capture.cs:200:13:200:19 | delegate call | false | -| in | Capture.cs:209:17:209:17 | i | Capture.cs:209:17:209:21 | SSA def(i) | Capture.cs:212:39:212:71 | SSA capture def(i) | Capture.cs:213:17:213:24 | access to event Exited | false | +| in | Capture.cs:209:17:209:17 | i | Capture.cs:209:17:209:21 | SSA def(i) | Capture.cs:212:39:212:71 | SSA capture def(i) | Capture.cs:213:17:213:24 | access to event Exited | true | | in | Capture.cs:229:13:229:13 | i | Capture.cs:232:9:232:13 | SSA def(i) | Capture.cs:231:9:231:49 | SSA capture def(i) | Capture.cs:233:9:233:12 | call to local function M2 | false | | in | Fields.cs:77:13:77:13 | f | Fields.cs:77:13:77:45 | SSA def(f) | Fields.cs:78:27:78:54 | SSA capture def(f) | Fields.cs:81:9:81:11 | delegate call | false | | in | Fields.cs:77:13:77:13 | f | Fields.cs:77:13:77:45 | SSA def(f) | Fields.cs:78:27:78:54 | SSA capture def(f) | Fields.cs:86:9:86:47 | call to method Select | true | -| in | Fields.cs:78:23:78:23 | a | Fields.cs:78:23:78:54 | SSA def(a) | Fields.cs:86:24:86:46 | SSA capture def(a) | Fields.cs:86:9:86:47 | call to method Select | false | -| in | Fields.cs:79:23:79:23 | b | Fields.cs:79:23:79:35 | SSA def(b) | Fields.cs:89:24:89:46 | SSA capture def(b) | Fields.cs:89:9:89:47 | call to method Select | false | +| in | Fields.cs:78:23:78:23 | a | Fields.cs:78:23:78:54 | SSA def(a) | Fields.cs:86:24:86:46 | SSA capture def(a) | Fields.cs:86:9:86:47 | call to method Select | true | +| in | Fields.cs:79:23:79:23 | b | Fields.cs:79:23:79:35 | SSA def(b) | Fields.cs:89:24:89:46 | SSA capture def(b) | Fields.cs:89:9:89:47 | call to method Select | true | | in | Properties.cs:73:13:73:13 | f | Properties.cs:73:13:73:32 | SSA def(f) | Properties.cs:74:27:74:54 | SSA capture def(f) | Properties.cs:77:9:77:11 | delegate call | false | | in | Properties.cs:73:13:73:13 | f | Properties.cs:73:13:73:32 | SSA def(f) | Properties.cs:74:27:74:54 | SSA capture def(f) | Properties.cs:82:9:82:47 | call to method Select | true | -| in | Properties.cs:74:23:74:23 | a | Properties.cs:74:23:74:54 | SSA def(a) | Properties.cs:82:24:82:46 | SSA capture def(a) | Properties.cs:82:9:82:47 | call to method Select | false | -| in | Properties.cs:75:23:75:23 | b | Properties.cs:75:23:75:35 | SSA def(b) | Properties.cs:85:24:85:46 | SSA capture def(b) | Properties.cs:85:9:85:47 | call to method Select | false | +| in | Properties.cs:74:23:74:23 | a | Properties.cs:74:23:74:54 | SSA def(a) | Properties.cs:82:24:82:46 | SSA capture def(a) | Properties.cs:82:9:82:47 | call to method Select | true | +| in | Properties.cs:75:23:75:23 | b | Properties.cs:75:23:75:35 | SSA def(b) | Properties.cs:85:24:85:46 | SSA capture def(b) | Properties.cs:85:9:85:47 | call to method Select | true | | out | Capture.cs:6:16:6:16 | i | Capture.cs:13:13:13:17 | SSA def(i) | Capture.cs:38:9:38:11 | SSA call def(i) | Capture.cs:38:9:38:11 | delegate call | false | | out | Capture.cs:8:13:8:13 | x | Capture.cs:15:13:15:17 | SSA def(x) | Capture.cs:38:9:38:11 | SSA call def(x) | Capture.cs:38:9:38:11 | delegate call | false | | out | Capture.cs:8:13:8:13 | x | Capture.cs:15:13:15:17 | SSA def(x) | Capture.cs:44:9:44:12 | SSA call def(x) | Capture.cs:44:9:44:12 | call to method M | true | | out | Capture.cs:29:13:29:13 | z | Capture.cs:30:28:30:32 | SSA def(z) | Capture.cs:32:9:32:11 | SSA call def(z) | Capture.cs:32:9:32:11 | delegate call | false | | out | Capture.cs:50:20:50:20 | a | Capture.cs:52:28:52:40 | SSA def(a) | Capture.cs:53:9:53:11 | SSA call def(a) | Capture.cs:53:9:53:11 | delegate call | false | -| out | Capture.cs:59:13:59:13 | i | Capture.cs:60:36:60:38 | SSA def(i) | Capture.cs:61:9:61:25 | SSA call def(i) | Capture.cs:61:9:61:25 | call to method Select | false | -| out | Capture.cs:75:13:75:13 | i | Capture.cs:76:80:76:80 | SSA def(i) | Capture.cs:77:9:77:25 | SSA call def(i) | Capture.cs:77:9:77:25 | call to method Select | false | +| out | Capture.cs:59:13:59:13 | i | Capture.cs:60:36:60:38 | SSA def(i) | Capture.cs:61:9:61:25 | SSA call def(i) | Capture.cs:61:9:61:25 | call to method Select | true | +| out | Capture.cs:75:13:75:13 | i | Capture.cs:76:80:76:80 | SSA def(i) | Capture.cs:77:9:77:25 | SSA call def(i) | Capture.cs:77:9:77:25 | call to method Select | true | | out | Capture.cs:130:13:130:13 | c | Capture.cs:133:13:133:17 | SSA def(c) | Capture.cs:136:9:136:12 | SSA call def(c) | Capture.cs:136:9:136:12 | call to local function M3 | false | | out | Capture.cs:139:13:139:13 | d | Capture.cs:142:13:142:17 | SSA def(d) | Capture.cs:144:9:144:12 | SSA call def(d) | Capture.cs:144:9:144:12 | call to local function M4 | false | | out | Capture.cs:168:13:168:13 | h | Capture.cs:174:17:174:21 | SSA def(h) | Capture.cs:176:13:176:16 | SSA call def(h) | Capture.cs:176:13:176:16 | call to local function M9 | false | diff --git a/csharp/ql/test/query-tests/Security Features/CWE-022/ZipSlip/ZipSlip.expected b/csharp/ql/test/query-tests/Security Features/CWE-022/ZipSlip/ZipSlip.expected index 223fcf616c2..ccfaf885369 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-022/ZipSlip/ZipSlip.expected +++ b/csharp/ql/test/query-tests/Security Features/CWE-022/ZipSlip/ZipSlip.expected @@ -1,25 +1,45 @@ edges -| ZipSlip.cs:16:52:16:65 | access to property FullName : String | ZipSlip.cs:32:41:32:52 | access to local variable destFilePath | -| ZipSlip.cs:16:52:16:65 | access to property FullName : String | ZipSlip.cs:36:45:36:56 | access to local variable destFilePath | -| ZipSlip.cs:16:52:16:65 | access to property FullName : String | ZipSlip.cs:40:41:40:52 | access to local variable destFilePath | -| ZipSlip.cs:19:31:19:44 | access to property FullName : String | ZipSlip.cs:24:41:24:52 | access to local variable destFileName | -| ZipSlip.cs:62:72:62:85 | access to property FullName : String | ZipSlip.cs:69:74:69:85 | access to local variable destFilePath | -| ZipSlip.cs:62:72:62:85 | access to property FullName : String | ZipSlip.cs:76:71:76:82 | access to local variable destFilePath | -| ZipSlip.cs:62:72:62:85 | access to property FullName : String | ZipSlip.cs:83:57:83:68 | access to local variable destFilePath | -| ZipSlip.cs:62:72:62:85 | access to property FullName : String | ZipSlip.cs:91:58:91:69 | access to local variable destFilePath | -| ZipSlipBad.cs:9:59:9:72 | access to property FullName : String | ZipSlipBad.cs:10:29:10:40 | access to local variable destFileName | +| ZipSlip.cs:16:35:16:66 | call to method GetFullPath : String | ZipSlip.cs:31:71:31:78 | access to local variable fullPath : String | +| ZipSlip.cs:16:35:16:66 | call to method GetFullPath : String | ZipSlip.cs:39:81:39:88 | access to local variable fullPath : String | +| ZipSlip.cs:16:52:16:65 | access to property FullName : String | ZipSlip.cs:16:35:16:66 | call to method GetFullPath : String | +| ZipSlip.cs:19:31:19:44 | access to property FullName : String | ZipSlip.cs:23:71:23:74 | access to local variable file : String | +| ZipSlip.cs:23:43:23:75 | call to method Combine : String | ZipSlip.cs:24:41:24:52 | access to local variable destFileName | +| ZipSlip.cs:23:71:23:74 | access to local variable file : String | ZipSlip.cs:23:43:23:75 | call to method Combine : String | +| ZipSlip.cs:31:43:31:79 | call to method Combine : String | ZipSlip.cs:32:41:32:52 | access to local variable destFilePath | +| ZipSlip.cs:31:43:31:79 | call to method Combine : String | ZipSlip.cs:36:45:36:56 | access to local variable destFilePath | +| ZipSlip.cs:31:71:31:78 | access to local variable fullPath : String | ZipSlip.cs:31:43:31:79 | call to method Combine : String | +| ZipSlip.cs:39:36:39:90 | call to method GetFullPath : String | ZipSlip.cs:40:41:40:52 | access to local variable destFilePath | +| ZipSlip.cs:39:53:39:89 | call to method Combine : String | ZipSlip.cs:39:36:39:90 | call to method GetFullPath : String | +| ZipSlip.cs:39:81:39:88 | access to local variable fullPath : String | ZipSlip.cs:39:53:39:89 | call to method Combine : String | +| ZipSlip.cs:62:47:62:86 | call to method Combine : String | ZipSlip.cs:69:74:69:85 | access to local variable destFilePath | +| ZipSlip.cs:62:47:62:86 | call to method Combine : String | ZipSlip.cs:76:71:76:82 | access to local variable destFilePath | +| ZipSlip.cs:62:47:62:86 | call to method Combine : String | ZipSlip.cs:83:57:83:68 | access to local variable destFilePath | +| ZipSlip.cs:62:47:62:86 | call to method Combine : String | ZipSlip.cs:91:58:91:69 | access to local variable destFilePath | +| ZipSlip.cs:62:72:62:85 | access to property FullName : String | ZipSlip.cs:62:47:62:86 | call to method Combine : String | +| ZipSlipBad.cs:9:31:9:73 | call to method Combine : String | ZipSlipBad.cs:10:29:10:40 | access to local variable destFileName | +| ZipSlipBad.cs:9:59:9:72 | access to property FullName : String | ZipSlipBad.cs:9:31:9:73 | call to method Combine : String | nodes +| ZipSlip.cs:16:35:16:66 | call to method GetFullPath : String | semmle.label | call to method GetFullPath : String | | ZipSlip.cs:16:52:16:65 | access to property FullName : String | semmle.label | access to property FullName : String | | ZipSlip.cs:19:31:19:44 | access to property FullName : String | semmle.label | access to property FullName : String | +| ZipSlip.cs:23:43:23:75 | call to method Combine : String | semmle.label | call to method Combine : String | +| ZipSlip.cs:23:71:23:74 | access to local variable file : String | semmle.label | access to local variable file : String | | ZipSlip.cs:24:41:24:52 | access to local variable destFileName | semmle.label | access to local variable destFileName | +| ZipSlip.cs:31:43:31:79 | call to method Combine : String | semmle.label | call to method Combine : String | +| ZipSlip.cs:31:71:31:78 | access to local variable fullPath : String | semmle.label | access to local variable fullPath : String | | ZipSlip.cs:32:41:32:52 | access to local variable destFilePath | semmle.label | access to local variable destFilePath | | ZipSlip.cs:36:45:36:56 | access to local variable destFilePath | semmle.label | access to local variable destFilePath | +| ZipSlip.cs:39:36:39:90 | call to method GetFullPath : String | semmle.label | call to method GetFullPath : String | +| ZipSlip.cs:39:53:39:89 | call to method Combine : String | semmle.label | call to method Combine : String | +| ZipSlip.cs:39:81:39:88 | access to local variable fullPath : String | semmle.label | access to local variable fullPath : String | | ZipSlip.cs:40:41:40:52 | access to local variable destFilePath | semmle.label | access to local variable destFilePath | +| ZipSlip.cs:62:47:62:86 | call to method Combine : String | semmle.label | call to method Combine : String | | ZipSlip.cs:62:72:62:85 | access to property FullName : String | semmle.label | access to property FullName : String | | ZipSlip.cs:69:74:69:85 | access to local variable destFilePath | semmle.label | access to local variable destFilePath | | ZipSlip.cs:76:71:76:82 | access to local variable destFilePath | semmle.label | access to local variable destFilePath | | ZipSlip.cs:83:57:83:68 | access to local variable destFilePath | semmle.label | access to local variable destFilePath | | ZipSlip.cs:91:58:91:69 | access to local variable destFilePath | semmle.label | access to local variable destFilePath | +| ZipSlipBad.cs:9:31:9:73 | call to method Combine : String | semmle.label | call to method Combine : String | | ZipSlipBad.cs:9:59:9:72 | access to property FullName : String | semmle.label | access to property FullName : String | | ZipSlipBad.cs:10:29:10:40 | access to local variable destFileName | semmle.label | access to local variable destFileName | #select diff --git a/csharp/ql/test/query-tests/Security Features/CWE-078/CommandInjection.expected b/csharp/ql/test/query-tests/Security Features/CWE-078/CommandInjection.expected index a87ff6764ce..254f5581744 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-078/CommandInjection.expected +++ b/csharp/ql/test/query-tests/Security Features/CWE-078/CommandInjection.expected @@ -1,13 +1,15 @@ edges -| CommandInjection.cs:25:32:25:46 | access to field categoryTextBox : TextBox | CommandInjection.cs:26:27:26:47 | ... + ... | -| CommandInjection.cs:25:32:25:46 | access to field categoryTextBox : TextBox | CommandInjection.cs:26:50:26:66 | ... + ... | -| CommandInjection.cs:25:32:25:46 | access to field categoryTextBox : TextBox | CommandInjection.cs:28:63:28:71 | access to local variable userInput | -| CommandInjection.cs:25:32:25:46 | access to field categoryTextBox : TextBox | CommandInjection.cs:28:74:28:82 | access to local variable userInput | -| CommandInjection.cs:25:32:25:46 | access to field categoryTextBox : TextBox | CommandInjection.cs:32:39:32:47 | access to local variable userInput | -| CommandInjection.cs:25:32:25:46 | access to field categoryTextBox : TextBox | CommandInjection.cs:33:40:33:48 | access to local variable userInput | -| CommandInjection.cs:25:32:25:46 | access to field categoryTextBox : TextBox | CommandInjection.cs:34:47:34:55 | access to local variable userInput | +| CommandInjection.cs:25:32:25:46 | access to field categoryTextBox : TextBox | CommandInjection.cs:25:32:25:51 | access to property Text : String | +| CommandInjection.cs:25:32:25:51 | access to property Text : String | CommandInjection.cs:26:27:26:47 | ... + ... | +| CommandInjection.cs:25:32:25:51 | access to property Text : String | CommandInjection.cs:26:50:26:66 | ... + ... | +| CommandInjection.cs:25:32:25:51 | access to property Text : String | CommandInjection.cs:28:63:28:71 | access to local variable userInput | +| CommandInjection.cs:25:32:25:51 | access to property Text : String | CommandInjection.cs:28:74:28:82 | access to local variable userInput | +| CommandInjection.cs:25:32:25:51 | access to property Text : String | CommandInjection.cs:32:39:32:47 | access to local variable userInput | +| CommandInjection.cs:25:32:25:51 | access to property Text : String | CommandInjection.cs:33:40:33:48 | access to local variable userInput | +| CommandInjection.cs:25:32:25:51 | access to property Text : String | CommandInjection.cs:34:47:34:55 | access to local variable userInput | nodes | CommandInjection.cs:25:32:25:46 | access to field categoryTextBox : TextBox | semmle.label | access to field categoryTextBox : TextBox | +| CommandInjection.cs:25:32:25:51 | access to property Text : String | semmle.label | access to property Text : String | | CommandInjection.cs:26:27:26:47 | ... + ... | semmle.label | ... + ... | | CommandInjection.cs:26:50:26:66 | ... + ... | semmle.label | ... + ... | | CommandInjection.cs:28:63:28:71 | access to local variable userInput | semmle.label | access to local variable userInput | diff --git a/csharp/ql/test/query-tests/Security Features/CWE-079/XSS/XSS.expected b/csharp/ql/test/query-tests/Security Features/CWE-079/XSS/XSS.expected index 81946f1054e..36d8ecfb339 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-079/XSS/XSS.expected +++ b/csharp/ql/test/query-tests/Security Features/CWE-079/XSS/XSS.expected @@ -2,11 +2,16 @@ edges | XSSAspNet.cs:20:25:20:43 | access to property QueryString : NameValueCollection | XSSAspNet.cs:27:30:27:34 | access to local variable sayHi | | XSSAspNet.cs:20:25:20:43 | access to property QueryString : NameValueCollection | XSSAspNet.cs:37:40:37:44 | access to local variable sayHi | | XSSAspNet.cs:44:28:44:46 | access to property QueryString : NameValueCollection | XSSAspNet.cs:44:28:44:55 | access to indexer | -| XSSAspNetCore.cs:21:52:21:64 | access to property Query : IQueryCollection | XSSAspNetCore.cs:21:52:21:76 | call to operator implicit conversion | +| XSSAspNetCore.cs:21:52:21:64 | access to property Query : IQueryCollection | XSSAspNetCore.cs:21:52:21:76 | access to indexer : StringValues | +| XSSAspNetCore.cs:21:52:21:76 | access to indexer : StringValues | XSSAspNetCore.cs:21:52:21:76 | call to operator implicit conversion | | XSSAspNetCore.cs:40:56:40:58 | foo : String | XSSAspNetCore.cs:44:51:44:53 | access to parameter foo | -| XSSAspNetCore.cs:58:43:58:55 | access to property Query : IQueryCollection | XSSAspNetCore.cs:58:43:58:73 | call to method ToString | +| XSSAspNetCore.cs:58:43:58:55 | access to property Query : IQueryCollection | XSSAspNetCore.cs:58:43:58:62 | access to indexer : StringValues | +| XSSAspNetCore.cs:58:43:58:62 | access to indexer : StringValues | XSSAspNetCore.cs:58:43:58:73 | call to method ToString | +| XSSAspNetCore.cs:61:44:61:56 | access to property Query : IQueryCollection | XSSAspNetCore.cs:61:44:61:63 | access to indexer : StringValues | | XSSAspNetCore.cs:61:44:61:56 | access to property Query : IQueryCollection | XSSAspNetCore.cs:61:44:61:66 | access to indexer | -| XSSAspNetCore.cs:72:51:72:65 | access to property Headers : IHeaderDictionary | XSSAspNetCore.cs:72:51:72:72 | call to operator implicit conversion | +| XSSAspNetCore.cs:61:44:61:63 | access to indexer : StringValues | XSSAspNetCore.cs:61:44:61:66 | access to indexer | +| XSSAspNetCore.cs:72:51:72:65 | access to property Headers : IHeaderDictionary | XSSAspNetCore.cs:72:51:72:72 | access to indexer : StringValues | +| XSSAspNetCore.cs:72:51:72:72 | access to indexer : StringValues | XSSAspNetCore.cs:72:51:72:72 | call to operator implicit conversion | #select | XSSAspNet.cs:27:30:27:34 | access to local variable sayHi | XSSAspNet.cs:20:25:20:43 | access to property QueryString : NameValueCollection | XSSAspNet.cs:27:30:27:34 | access to local variable sayHi | $@ flows to here and is written to HTML or JavaScript: System.Web.WebPages.WebPage.WriteLiteral() method. | XSSAspNet.cs:20:25:20:43 | access to property QueryString : NameValueCollection | User-provided value | | XSSAspNet.cs:37:40:37:44 | access to local variable sayHi | XSSAspNet.cs:20:25:20:43 | access to property QueryString : NameValueCollection | XSSAspNet.cs:37:40:37:44 | access to local variable sayHi | $@ flows to here and is written to HTML or JavaScript: System.Web.WebPages.WebPage.WriteLiteralTo() method. | XSSAspNet.cs:20:25:20:43 | access to property QueryString : NameValueCollection | User-provided value | diff --git a/csharp/ql/test/query-tests/Security Features/CWE-089/SqlInjection.expected b/csharp/ql/test/query-tests/Security Features/CWE-089/SqlInjection.expected index b035cc46b1b..61dffee741f 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-089/SqlInjection.expected +++ b/csharp/ql/test/query-tests/Security Features/CWE-089/SqlInjection.expected @@ -1,12 +1,16 @@ edges -| SqlInjection.cs:38:21:38:35 | access to field categoryTextBox : TextBox | SqlInjection.cs:39:50:39:55 | access to local variable query1 | -| SqlInjection.cs:73:33:73:47 | access to field categoryTextBox : TextBox | SqlInjection.cs:74:56:74:61 | access to local variable query1 | -| SqlInjection.cs:73:33:73:47 | access to field categoryTextBox : TextBox | SqlInjection.cs:75:55:75:60 | access to local variable query1 | +| SqlInjection.cs:38:21:38:35 | access to field categoryTextBox : TextBox | SqlInjection.cs:38:21:38:40 | access to property Text : String | +| SqlInjection.cs:38:21:38:40 | access to property Text : String | SqlInjection.cs:39:50:39:55 | access to local variable query1 | +| SqlInjection.cs:73:33:73:47 | access to field categoryTextBox : TextBox | SqlInjection.cs:73:33:73:52 | access to property Text : String | +| SqlInjection.cs:73:33:73:52 | access to property Text : String | SqlInjection.cs:74:56:74:61 | access to local variable query1 | +| SqlInjection.cs:73:33:73:52 | access to property Text : String | SqlInjection.cs:75:55:75:60 | access to local variable query1 | | SqlInjection.cs:87:21:87:29 | access to property Text : String | SqlInjection.cs:88:50:88:55 | access to local variable query1 | nodes | SqlInjection.cs:38:21:38:35 | access to field categoryTextBox : TextBox | semmle.label | access to field categoryTextBox : TextBox | +| SqlInjection.cs:38:21:38:40 | access to property Text : String | semmle.label | access to property Text : String | | SqlInjection.cs:39:50:39:55 | access to local variable query1 | semmle.label | access to local variable query1 | | SqlInjection.cs:73:33:73:47 | access to field categoryTextBox : TextBox | semmle.label | access to field categoryTextBox : TextBox | +| SqlInjection.cs:73:33:73:52 | access to property Text : String | semmle.label | access to property Text : String | | SqlInjection.cs:74:56:74:61 | access to local variable query1 | semmle.label | access to local variable query1 | | SqlInjection.cs:75:55:75:60 | access to local variable query1 | semmle.label | access to local variable query1 | | SqlInjection.cs:87:21:87:29 | access to property Text : String | semmle.label | access to property Text : String | diff --git a/csharp/ql/test/query-tests/Security Features/CWE-112/MissingXMLValidation.expected b/csharp/ql/test/query-tests/Security Features/CWE-112/MissingXMLValidation.expected index b9abafda2f4..38c31c17825 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-112/MissingXMLValidation.expected +++ b/csharp/ql/test/query-tests/Security Features/CWE-112/MissingXMLValidation.expected @@ -1,16 +1,26 @@ edges -| MissingXMLValidation.cs:14:34:14:56 | access to property QueryString : NameValueCollection | MissingXMLValidation.cs:18:26:18:58 | object creation of type StringReader | -| MissingXMLValidation.cs:14:34:14:56 | access to property QueryString : NameValueCollection | MissingXMLValidation.cs:23:26:23:58 | object creation of type StringReader | -| MissingXMLValidation.cs:14:34:14:56 | access to property QueryString : NameValueCollection | MissingXMLValidation.cs:29:26:29:58 | object creation of type StringReader | -| MissingXMLValidation.cs:14:34:14:56 | access to property QueryString : NameValueCollection | MissingXMLValidation.cs:37:26:37:58 | object creation of type StringReader | -| MissingXMLValidation.cs:14:34:14:56 | access to property QueryString : NameValueCollection | MissingXMLValidation.cs:47:26:47:58 | object creation of type StringReader | +| MissingXMLValidation.cs:14:34:14:56 | access to property QueryString : NameValueCollection | MissingXMLValidation.cs:18:43:18:57 | access to local variable userProvidedXml : String | +| MissingXMLValidation.cs:14:34:14:56 | access to property QueryString : NameValueCollection | MissingXMLValidation.cs:23:43:23:57 | access to local variable userProvidedXml : String | +| MissingXMLValidation.cs:14:34:14:56 | access to property QueryString : NameValueCollection | MissingXMLValidation.cs:29:43:29:57 | access to local variable userProvidedXml : String | +| MissingXMLValidation.cs:14:34:14:56 | access to property QueryString : NameValueCollection | MissingXMLValidation.cs:37:43:37:57 | access to local variable userProvidedXml : String | +| MissingXMLValidation.cs:14:34:14:56 | access to property QueryString : NameValueCollection | MissingXMLValidation.cs:47:43:47:57 | access to local variable userProvidedXml : String | +| MissingXMLValidation.cs:18:43:18:57 | access to local variable userProvidedXml : String | MissingXMLValidation.cs:18:26:18:58 | object creation of type StringReader | +| MissingXMLValidation.cs:23:43:23:57 | access to local variable userProvidedXml : String | MissingXMLValidation.cs:23:26:23:58 | object creation of type StringReader | +| MissingXMLValidation.cs:29:43:29:57 | access to local variable userProvidedXml : String | MissingXMLValidation.cs:29:26:29:58 | object creation of type StringReader | +| MissingXMLValidation.cs:37:43:37:57 | access to local variable userProvidedXml : String | MissingXMLValidation.cs:37:26:37:58 | object creation of type StringReader | +| MissingXMLValidation.cs:47:43:47:57 | access to local variable userProvidedXml : String | MissingXMLValidation.cs:47:26:47:58 | object creation of type StringReader | nodes | MissingXMLValidation.cs:14:34:14:56 | access to property QueryString : NameValueCollection | semmle.label | access to property QueryString : NameValueCollection | | MissingXMLValidation.cs:18:26:18:58 | object creation of type StringReader | semmle.label | object creation of type StringReader | +| MissingXMLValidation.cs:18:43:18:57 | access to local variable userProvidedXml : String | semmle.label | access to local variable userProvidedXml : String | | MissingXMLValidation.cs:23:26:23:58 | object creation of type StringReader | semmle.label | object creation of type StringReader | +| MissingXMLValidation.cs:23:43:23:57 | access to local variable userProvidedXml : String | semmle.label | access to local variable userProvidedXml : String | | MissingXMLValidation.cs:29:26:29:58 | object creation of type StringReader | semmle.label | object creation of type StringReader | +| MissingXMLValidation.cs:29:43:29:57 | access to local variable userProvidedXml : String | semmle.label | access to local variable userProvidedXml : String | | MissingXMLValidation.cs:37:26:37:58 | object creation of type StringReader | semmle.label | object creation of type StringReader | +| MissingXMLValidation.cs:37:43:37:57 | access to local variable userProvidedXml : String | semmle.label | access to local variable userProvidedXml : String | | MissingXMLValidation.cs:47:26:47:58 | object creation of type StringReader | semmle.label | object creation of type StringReader | +| MissingXMLValidation.cs:47:43:47:57 | access to local variable userProvidedXml : String | semmle.label | access to local variable userProvidedXml : String | #select | MissingXMLValidation.cs:18:26:18:58 | object creation of type StringReader | MissingXMLValidation.cs:14:34:14:56 | access to property QueryString : NameValueCollection | MissingXMLValidation.cs:18:26:18:58 | object creation of type StringReader | $@ flows to here and is processed as XML without validation because there is no 'XmlReaderSettings' instance specifying schema validation. | MissingXMLValidation.cs:14:34:14:56 | access to property QueryString | User-provided value | | MissingXMLValidation.cs:23:26:23:58 | object creation of type StringReader | MissingXMLValidation.cs:14:34:14:56 | access to property QueryString : NameValueCollection | MissingXMLValidation.cs:23:26:23:58 | object creation of type StringReader | $@ flows to here and is processed as XML without validation because the 'XmlReaderSettings' instance does not specify the 'ValidationType' as 'Schema'. | MissingXMLValidation.cs:14:34:14:56 | access to property QueryString | User-provided value | diff --git a/csharp/ql/test/query-tests/Security Features/CWE-338/InsecureRandomness.expected b/csharp/ql/test/query-tests/Security Features/CWE-338/InsecureRandomness.expected index 8e051c94464..138451c31dc 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-338/InsecureRandomness.expected +++ b/csharp/ql/test/query-tests/Security Features/CWE-338/InsecureRandomness.expected @@ -7,7 +7,8 @@ edges | InsecureRandomness.cs:29:57:29:60 | access to local variable data [[]] : Int32 | InsecureRandomness.cs:29:27:29:61 | call to method GetString : String | | InsecureRandomness.cs:31:16:31:21 | access to local variable result [[]] : String | InsecureRandomness.cs:31:16:31:32 | call to method ToString : String | | InsecureRandomness.cs:31:16:31:32 | call to method ToString : String | InsecureRandomness.cs:12:27:12:50 | call to method InsecureRandomString | -| InsecureRandomness.cs:60:31:60:39 | call to method Next : Int32 | InsecureRandomness.cs:62:16:62:32 | call to method ToString : String | +| InsecureRandomness.cs:60:31:60:39 | call to method Next : Int32 | InsecureRandomness.cs:62:16:62:21 | access to local variable result : String | +| InsecureRandomness.cs:62:16:62:21 | access to local variable result : String | InsecureRandomness.cs:62:16:62:32 | call to method ToString : String | | InsecureRandomness.cs:62:16:62:32 | call to method ToString : String | InsecureRandomness.cs:13:20:13:56 | call to method InsecureRandomStringFromSelection | | InsecureRandomness.cs:72:31:72:39 | call to method Next : Int32 | InsecureRandomness.cs:74:16:74:21 | access to local variable result : String | | InsecureRandomness.cs:74:16:74:21 | access to local variable result : String | InsecureRandomness.cs:14:20:14:54 | call to method InsecureRandomStringFromIndexer | @@ -24,6 +25,7 @@ nodes | InsecureRandomness.cs:31:16:31:21 | access to local variable result [[]] : String | semmle.label | access to local variable result [[]] : String | | InsecureRandomness.cs:31:16:31:32 | call to method ToString : String | semmle.label | call to method ToString : String | | InsecureRandomness.cs:60:31:60:39 | call to method Next : Int32 | semmle.label | call to method Next : Int32 | +| InsecureRandomness.cs:62:16:62:21 | access to local variable result : String | semmle.label | access to local variable result : String | | InsecureRandomness.cs:62:16:62:32 | call to method ToString : String | semmle.label | call to method ToString : String | | InsecureRandomness.cs:72:31:72:39 | call to method Next : Int32 | semmle.label | call to method Next : Int32 | | InsecureRandomness.cs:74:16:74:21 | access to local variable result : String | semmle.label | access to local variable result : String | diff --git a/csharp/ql/test/query-tests/Security Features/CWE-601/UrlRedirect/UrlRedirect.expected b/csharp/ql/test/query-tests/Security Features/CWE-601/UrlRedirect/UrlRedirect.expected index afcc216fc02..2ed9af3f8f2 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-601/UrlRedirect/UrlRedirect.expected +++ b/csharp/ql/test/query-tests/Security Features/CWE-601/UrlRedirect/UrlRedirect.expected @@ -4,15 +4,19 @@ edges | UrlRedirect.cs:39:44:39:66 | access to property QueryString : NameValueCollection | UrlRedirect.cs:39:44:39:74 | access to indexer | | UrlRedirect.cs:40:47:40:69 | access to property QueryString : NameValueCollection | UrlRedirect.cs:40:47:40:77 | access to indexer | | UrlRedirectCore.cs:15:44:15:48 | value : String | UrlRedirectCore.cs:18:22:18:26 | access to parameter value | -| UrlRedirectCore.cs:15:44:15:48 | value : String | UrlRedirectCore.cs:21:44:21:48 | call to operator implicit conversion | -| UrlRedirectCore.cs:15:44:15:48 | value : String | UrlRedirectCore.cs:27:46:27:50 | call to operator implicit conversion | +| UrlRedirectCore.cs:15:44:15:48 | value : String | UrlRedirectCore.cs:21:44:21:48 | access to parameter value : String | +| UrlRedirectCore.cs:15:44:15:48 | value : String | UrlRedirectCore.cs:27:46:27:50 | access to parameter value : String | | UrlRedirectCore.cs:15:44:15:48 | value : String | UrlRedirectCore.cs:33:66:33:70 | access to parameter value | -| UrlRedirectCore.cs:15:44:15:48 | value : String | UrlRedirectCore.cs:36:49:36:53 | call to operator implicit conversion | +| UrlRedirectCore.cs:15:44:15:48 | value : String | UrlRedirectCore.cs:36:49:36:53 | access to parameter value : String | | UrlRedirectCore.cs:15:44:15:48 | value : String | UrlRedirectCore.cs:39:69:39:73 | access to parameter value | | UrlRedirectCore.cs:15:44:15:48 | value : String | UrlRedirectCore.cs:42:39:42:53 | ... + ... | +| UrlRedirectCore.cs:21:44:21:48 | access to parameter value : String | UrlRedirectCore.cs:21:44:21:48 | call to operator implicit conversion | +| UrlRedirectCore.cs:27:46:27:50 | access to parameter value : String | UrlRedirectCore.cs:27:46:27:50 | call to operator implicit conversion | +| UrlRedirectCore.cs:36:49:36:53 | access to parameter value : String | UrlRedirectCore.cs:36:49:36:53 | call to operator implicit conversion | | UrlRedirectCore.cs:47:51:47:55 | value : String | UrlRedirectCore.cs:50:28:50:32 | access to parameter value | -| UrlRedirectCore.cs:47:51:47:55 | value : String | UrlRedirectCore.cs:55:32:55:45 | object creation of type Uri | +| UrlRedirectCore.cs:47:51:47:55 | value : String | UrlRedirectCore.cs:55:40:55:44 | access to parameter value : String | | UrlRedirectCore.cs:47:51:47:55 | value : String | UrlRedirectCore.cs:58:31:58:35 | access to parameter value | +| UrlRedirectCore.cs:55:40:55:44 | access to parameter value : String | UrlRedirectCore.cs:55:32:55:45 | object creation of type Uri | nodes | UrlRedirect.cs:14:31:14:53 | access to property QueryString : NameValueCollection | semmle.label | access to property QueryString : NameValueCollection | | UrlRedirect.cs:14:31:14:61 | access to indexer | semmle.label | access to indexer | @@ -24,15 +28,19 @@ nodes | UrlRedirect.cs:49:29:49:31 | access to local variable url | semmle.label | access to local variable url | | UrlRedirectCore.cs:15:44:15:48 | value : String | semmle.label | value : String | | UrlRedirectCore.cs:18:22:18:26 | access to parameter value | semmle.label | access to parameter value | +| UrlRedirectCore.cs:21:44:21:48 | access to parameter value : String | semmle.label | access to parameter value : String | | UrlRedirectCore.cs:21:44:21:48 | call to operator implicit conversion | semmle.label | call to operator implicit conversion | +| UrlRedirectCore.cs:27:46:27:50 | access to parameter value : String | semmle.label | access to parameter value : String | | UrlRedirectCore.cs:27:46:27:50 | call to operator implicit conversion | semmle.label | call to operator implicit conversion | | UrlRedirectCore.cs:33:66:33:70 | access to parameter value | semmle.label | access to parameter value | +| UrlRedirectCore.cs:36:49:36:53 | access to parameter value : String | semmle.label | access to parameter value : String | | UrlRedirectCore.cs:36:49:36:53 | call to operator implicit conversion | semmle.label | call to operator implicit conversion | | UrlRedirectCore.cs:39:69:39:73 | access to parameter value | semmle.label | access to parameter value | | UrlRedirectCore.cs:42:39:42:53 | ... + ... | semmle.label | ... + ... | | UrlRedirectCore.cs:47:51:47:55 | value : String | semmle.label | value : String | | UrlRedirectCore.cs:50:28:50:32 | access to parameter value | semmle.label | access to parameter value | | UrlRedirectCore.cs:55:32:55:45 | object creation of type Uri | semmle.label | object creation of type Uri | +| UrlRedirectCore.cs:55:40:55:44 | access to parameter value : String | semmle.label | access to parameter value : String | | UrlRedirectCore.cs:58:31:58:35 | access to parameter value | semmle.label | access to parameter value | #select | UrlRedirect.cs:14:31:14:61 | access to indexer | UrlRedirect.cs:14:31:14:53 | access to property QueryString : NameValueCollection | UrlRedirect.cs:14:31:14:61 | access to indexer | Untrusted URL redirection due to $@. | UrlRedirect.cs:14:31:14:53 | access to property QueryString | user-provided value | diff --git a/csharp/ql/test/query-tests/Security Features/CWE-807/ConditionalBypass.expected b/csharp/ql/test/query-tests/Security Features/CWE-807/ConditionalBypass.expected index 7898c01c3b5..72c7464ba38 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-807/ConditionalBypass.expected +++ b/csharp/ql/test/query-tests/Security Features/CWE-807/ConditionalBypass.expected @@ -1,23 +1,45 @@ edges | ConditionalBypass.cs:14:26:14:48 | access to property QueryString : NameValueCollection | ConditionalBypass.cs:18:13:18:30 | ... == ... | -| ConditionalBypass.cs:21:34:21:52 | access to property Cookies : HttpCookieCollection | ConditionalBypass.cs:24:13:24:45 | call to method Equals | -| ConditionalBypass.cs:21:34:21:52 | access to property Cookies : HttpCookieCollection | ConditionalBypass.cs:29:13:29:40 | ... == ... | -| ConditionalBypass.cs:44:32:44:66 | call to method GetHostByAddress : IPHostEntry | ConditionalBypass.cs:46:13:46:46 | ... == ... | -| ConditionalBypass.cs:44:32:44:66 | call to method GetHostByAddress : IPHostEntry | ConditionalBypass.cs:51:13:51:29 | access to property HostName | -| ConditionalBypass.cs:72:34:72:52 | access to property Cookies : HttpCookieCollection | ConditionalBypass.cs:74:13:74:40 | ... == ... | -| ConditionalBypass.cs:85:34:85:52 | access to property Cookies : HttpCookieCollection | ConditionalBypass.cs:86:13:86:40 | ... == ... | +| ConditionalBypass.cs:21:34:21:52 | access to property Cookies : HttpCookieCollection | ConditionalBypass.cs:24:13:24:23 | access to local variable adminCookie : HttpCookie | +| ConditionalBypass.cs:21:34:21:52 | access to property Cookies : HttpCookieCollection | ConditionalBypass.cs:29:13:29:23 | access to local variable adminCookie : HttpCookie | +| ConditionalBypass.cs:24:13:24:23 | access to local variable adminCookie : HttpCookie | ConditionalBypass.cs:24:13:24:29 | access to property Value : String | +| ConditionalBypass.cs:24:13:24:29 | access to property Value : String | ConditionalBypass.cs:24:13:24:45 | call to method Equals | +| ConditionalBypass.cs:29:13:29:23 | access to local variable adminCookie : HttpCookie | ConditionalBypass.cs:29:13:29:29 | access to property Value : String | +| ConditionalBypass.cs:29:13:29:29 | access to property Value : String | ConditionalBypass.cs:29:13:29:40 | ... == ... | +| ConditionalBypass.cs:44:32:44:66 | call to method GetHostByAddress : IPHostEntry | ConditionalBypass.cs:46:13:46:20 | access to local variable hostInfo : IPHostEntry | +| ConditionalBypass.cs:44:32:44:66 | call to method GetHostByAddress : IPHostEntry | ConditionalBypass.cs:51:13:51:20 | access to local variable hostInfo : IPHostEntry | +| ConditionalBypass.cs:46:13:46:20 | access to local variable hostInfo : IPHostEntry | ConditionalBypass.cs:46:13:46:29 | access to property HostName : String | +| ConditionalBypass.cs:46:13:46:29 | access to property HostName : String | ConditionalBypass.cs:46:13:46:46 | ... == ... | +| ConditionalBypass.cs:51:13:51:20 | access to local variable hostInfo : IPHostEntry | ConditionalBypass.cs:51:13:51:29 | access to property HostName | +| ConditionalBypass.cs:72:34:72:52 | access to property Cookies : HttpCookieCollection | ConditionalBypass.cs:74:13:74:23 | access to local variable adminCookie : HttpCookie | +| ConditionalBypass.cs:74:13:74:23 | access to local variable adminCookie : HttpCookie | ConditionalBypass.cs:74:13:74:29 | access to property Value : String | +| ConditionalBypass.cs:74:13:74:29 | access to property Value : String | ConditionalBypass.cs:74:13:74:40 | ... == ... | +| ConditionalBypass.cs:85:34:85:52 | access to property Cookies : HttpCookieCollection | ConditionalBypass.cs:86:13:86:23 | access to local variable adminCookie : HttpCookie | +| ConditionalBypass.cs:86:13:86:23 | access to local variable adminCookie : HttpCookie | ConditionalBypass.cs:86:13:86:29 | access to property Value : String | +| ConditionalBypass.cs:86:13:86:29 | access to property Value : String | ConditionalBypass.cs:86:13:86:40 | ... == ... | nodes | ConditionalBypass.cs:14:26:14:48 | access to property QueryString : NameValueCollection | semmle.label | access to property QueryString : NameValueCollection | | ConditionalBypass.cs:18:13:18:30 | ... == ... | semmle.label | ... == ... | | ConditionalBypass.cs:21:34:21:52 | access to property Cookies : HttpCookieCollection | semmle.label | access to property Cookies : HttpCookieCollection | +| ConditionalBypass.cs:24:13:24:23 | access to local variable adminCookie : HttpCookie | semmle.label | access to local variable adminCookie : HttpCookie | +| ConditionalBypass.cs:24:13:24:29 | access to property Value : String | semmle.label | access to property Value : String | | ConditionalBypass.cs:24:13:24:45 | call to method Equals | semmle.label | call to method Equals | +| ConditionalBypass.cs:29:13:29:23 | access to local variable adminCookie : HttpCookie | semmle.label | access to local variable adminCookie : HttpCookie | +| ConditionalBypass.cs:29:13:29:29 | access to property Value : String | semmle.label | access to property Value : String | | ConditionalBypass.cs:29:13:29:40 | ... == ... | semmle.label | ... == ... | | ConditionalBypass.cs:44:32:44:66 | call to method GetHostByAddress : IPHostEntry | semmle.label | call to method GetHostByAddress : IPHostEntry | +| ConditionalBypass.cs:46:13:46:20 | access to local variable hostInfo : IPHostEntry | semmle.label | access to local variable hostInfo : IPHostEntry | +| ConditionalBypass.cs:46:13:46:29 | access to property HostName : String | semmle.label | access to property HostName : String | | ConditionalBypass.cs:46:13:46:46 | ... == ... | semmle.label | ... == ... | +| ConditionalBypass.cs:51:13:51:20 | access to local variable hostInfo : IPHostEntry | semmle.label | access to local variable hostInfo : IPHostEntry | | ConditionalBypass.cs:51:13:51:29 | access to property HostName | semmle.label | access to property HostName | | ConditionalBypass.cs:72:34:72:52 | access to property Cookies : HttpCookieCollection | semmle.label | access to property Cookies : HttpCookieCollection | +| ConditionalBypass.cs:74:13:74:23 | access to local variable adminCookie : HttpCookie | semmle.label | access to local variable adminCookie : HttpCookie | +| ConditionalBypass.cs:74:13:74:29 | access to property Value : String | semmle.label | access to property Value : String | | ConditionalBypass.cs:74:13:74:40 | ... == ... | semmle.label | ... == ... | | ConditionalBypass.cs:85:34:85:52 | access to property Cookies : HttpCookieCollection | semmle.label | access to property Cookies : HttpCookieCollection | +| ConditionalBypass.cs:86:13:86:23 | access to local variable adminCookie : HttpCookie | semmle.label | access to local variable adminCookie : HttpCookie | +| ConditionalBypass.cs:86:13:86:29 | access to property Value : String | semmle.label | access to property Value : String | | ConditionalBypass.cs:86:13:86:40 | ... == ... | semmle.label | ... == ... | #select | ConditionalBypass.cs:19:13:19:33 | call to method login | ConditionalBypass.cs:14:26:14:48 | access to property QueryString : NameValueCollection | ConditionalBypass.cs:18:13:18:30 | ... == ... | Sensitive method may not be executed depending on $@, which flows from $@. | ConditionalBypass.cs:18:13:18:30 | ... == ... | this condition | ConditionalBypass.cs:14:26:14:48 | access to property QueryString | user input | diff --git a/csharp/ql/test/query-tests/Security Features/CWE-838/InappropriateEncoding.expected b/csharp/ql/test/query-tests/Security Features/CWE-838/InappropriateEncoding.expected index 3bdac85df06..0dd5f0c1e2c 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-838/InappropriateEncoding.expected +++ b/csharp/ql/test/query-tests/Security Features/CWE-838/InappropriateEncoding.expected @@ -3,7 +3,8 @@ edges | InappropriateEncoding.cs:15:28:15:40 | call to method Encode : String | InappropriateEncoding.cs:20:46:20:51 | access to local variable query1 | | InappropriateEncoding.cs:36:28:36:55 | call to method UrlEncode : String | InappropriateEncoding.cs:37:32:37:43 | access to local variable encodedValue | | InappropriateEncoding.cs:36:28:36:55 | call to method UrlEncode : String | InappropriateEncoding.cs:38:22:38:59 | ... + ... | -| InappropriateEncoding.cs:36:28:36:55 | call to method UrlEncode : String | InappropriateEncoding.cs:39:22:39:71 | call to method Format | +| InappropriateEncoding.cs:36:28:36:55 | call to method UrlEncode : String | InappropriateEncoding.cs:39:59:39:70 | access to local variable encodedValue : String | +| InappropriateEncoding.cs:39:59:39:70 | access to local variable encodedValue : String | InappropriateEncoding.cs:39:22:39:71 | call to method Format | | InappropriateEncoding.cs:57:28:57:56 | call to method HtmlEncode : String | InappropriateEncoding.cs:58:31:58:42 | access to local variable encodedValue | | InappropriateEncoding.cs:68:16:68:42 | call to method Replace : String | InappropriateEncoding.cs:15:28:15:40 | call to method Encode : String | | SqlEncode.cs:16:62:16:87 | call to method Replace : String | SqlEncode.cs:17:46:17:50 | access to local variable query | @@ -20,6 +21,7 @@ nodes | InappropriateEncoding.cs:37:32:37:43 | access to local variable encodedValue | semmle.label | access to local variable encodedValue | | InappropriateEncoding.cs:38:22:38:59 | ... + ... | semmle.label | ... + ... | | InappropriateEncoding.cs:39:22:39:71 | call to method Format | semmle.label | call to method Format | +| InappropriateEncoding.cs:39:59:39:70 | access to local variable encodedValue : String | semmle.label | access to local variable encodedValue : String | | InappropriateEncoding.cs:57:28:57:56 | call to method HtmlEncode : String | semmle.label | call to method HtmlEncode : String | | InappropriateEncoding.cs:58:31:58:42 | access to local variable encodedValue | semmle.label | access to local variable encodedValue | | InappropriateEncoding.cs:68:16:68:42 | call to method Replace : String | semmle.label | call to method Replace : String |