C#: Adopt shared SSA data-flow integration

This commit is contained in:
Tom Hvitved
2024-07-03 10:41:40 +02:00
parent fbcb4498fe
commit 89a2381165
11 changed files with 1718 additions and 937 deletions

View File

@@ -29,7 +29,7 @@ module BaseSsa {
) {
exists(ControlFlow::ControlFlow::BasicBlocks::EntryBlock entry |
c = entry.getCallable() and
// In case `c` has multiple bodies, we want each body to gets its own implicit
// In case `c` has multiple bodies, we want each body to get its own implicit
// entry definition. In case `c` doesn't have multiple bodies, the line below
// is simply the same as `bb = entry`, because `entry.getFirstNode().getASuccessor()`
// will be in the entry block.

View File

@@ -267,8 +267,9 @@ module VariableCapture {
private predicate closureFlowStep(ControlFlow::Nodes::ExprNode e1, ControlFlow::Nodes::ExprNode e2) {
e1 = LocalFlow::getALastEvalNode(e2)
or
exists(Ssa::Definition def |
LocalFlow::ssaDefAssigns(def.getAnUltimateDefinition(), e1) and
exists(Ssa::Definition def, AssignableDefinition adef |
LocalFlow::defAssigns(adef, _, e1) and
def.getAnUltimateDefinition().(Ssa::ExplicitDefinition).getADefinition() = adef and
exists(def.getAReadAtNode(e2))
)
}
@@ -492,6 +493,30 @@ module VariableCapture {
}
}
/** Provides logic related to SSA. */
module SsaFlow {
private module Impl = SsaImpl::DataFlowIntegration;
Impl::Node asNode(Node n) {
n = TSsaNode(result)
or
result.(Impl::ExprNode).getExpr() = n.(ExprNode).getControlFlowNode()
or
result.(Impl::ExprPostUpdateNode).getExpr() =
n.(PostUpdateNode).getPreUpdateNode().(ExprNode).getControlFlowNode()
or
result.(Impl::ParameterNode).getParameter() = n.(ExplicitParameterNode).getSsaDefinition()
}
predicate localFlowStep(SsaImpl::DefinitionExt def, Node nodeFrom, Node nodeTo, boolean isUseStep) {
Impl::localFlowStep(def, asNode(nodeFrom), asNode(nodeTo), isUseStep)
}
predicate localMustFlowStep(SsaImpl::DefinitionExt def, Node nodeFrom, Node nodeTo) {
Impl::localMustFlowStep(def, asNode(nodeFrom), asNode(nodeTo))
}
}
/** Provides predicates related to local data flow. */
module LocalFlow {
class LocalExprStepConfiguration extends ControlFlowReachabilityConfiguration {
@@ -617,105 +642,6 @@ module LocalFlow {
any(LocalExprStepConfiguration x).hasDefPath(_, value, def, cfnDef)
}
predicate ssaDefAssigns(Ssa::ExplicitDefinition ssaDef, ControlFlow::Nodes::ExprNode value) {
exists(AssignableDefinition def, ControlFlow::Node cfnDef |
any(LocalExprStepConfiguration conf).hasDefPath(_, value, def, cfnDef) and
ssaDef.getADefinition() = def and
ssaDef.getControlFlowNode() = cfnDef
)
}
/**
* An uncertain SSA definition. Either an uncertain explicit definition or an
* uncertain qualifier definition.
*
* Restricts `Ssa::UncertainDefinition` by excluding implicit call definitions,
* as we---conservatively---consider such definitions to be certain.
*/
class UncertainExplicitSsaDefinition extends Ssa::UncertainDefinition {
UncertainExplicitSsaDefinition() {
this instanceof Ssa::ExplicitDefinition
or
this =
any(Ssa::ImplicitQualifierDefinition qdef |
qdef.getQualifierDefinition() instanceof UncertainExplicitSsaDefinition
)
}
}
/** An SSA definition into which another SSA definition may flow. */
private class SsaInputDefinitionExtNode extends SsaDefinitionExtNode {
SsaInputDefinitionExtNode() {
def instanceof Ssa::PhiNode
or
def instanceof SsaImpl::PhiReadNode
or
def instanceof LocalFlow::UncertainExplicitSsaDefinition
}
}
/**
* Holds if `nodeFrom` is a last node referencing SSA definition `def`, which
* can reach `next`.
*/
private predicate localFlowSsaInputFromDef(
Node nodeFrom, SsaImpl::DefinitionExt def, SsaInputDefinitionExtNode next
) {
exists(ControlFlow::BasicBlock bb, int i |
SsaImpl::lastRefBeforeRedefExt(def, bb, i, next.getDefinitionExt()) and
def.definesAt(_, bb, i, _) and
def = getSsaDefinitionExt(nodeFrom) and
nodeFrom != next
)
}
/**
* Holds if `read` is a last node reading SSA definition `def`, which
* can reach `next`.
*/
predicate localFlowSsaInputFromRead(
Node read, SsaImpl::DefinitionExt def, SsaInputDefinitionExtNode next
) {
exists(ControlFlow::BasicBlock bb, int i |
SsaImpl::lastRefBeforeRedefExt(def, bb, i, next.getDefinitionExt()) and
read.asExprAtNode(bb.getNode(i)) instanceof AssignableRead
)
}
private SsaImpl::DefinitionExt getSsaDefinitionExt(Node n) {
result = n.(SsaDefinitionExtNode).getDefinitionExt()
or
result = n.(ExplicitParameterNode).getSsaDefinition()
}
/**
* Holds if there is a local use-use flow step from `nodeFrom` to `nodeTo`
* involving SSA definition `def`.
*/
predicate localSsaFlowStepUseUse(SsaImpl::DefinitionExt def, Node nodeFrom, Node nodeTo) {
exists(ControlFlow::Node cfnFrom, ControlFlow::Node cfnTo |
SsaImpl::adjacentReadPairSameVarExt(def, cfnFrom, cfnTo) and
nodeTo = TExprNode(cfnTo) and
nodeFrom = TExprNode(cfnFrom)
)
}
/**
* Holds if there is a local flow step from `nodeFrom` to `nodeTo` involving
* SSA definition `def`.
*/
predicate localSsaFlowStep(SsaImpl::DefinitionExt def, Node nodeFrom, Node nodeTo) {
// Flow from SSA definition/parameter to first read
def = getSsaDefinitionExt(nodeFrom) and
SsaImpl::firstReadSameVarExt(def, nodeTo.(ExprNode).getControlFlowNode())
or
// Flow from read to next read
localSsaFlowStepUseUse(def, nodeFrom.(PostUpdateNode).getPreUpdateNode(), nodeTo)
or
// Flow into phi (read)/uncertain SSA definition node from def
localFlowSsaInputFromDef(nodeFrom, def, nodeTo)
}
/**
* Holds if the source variable of SSA definition `def` is an instance field.
*/
@@ -800,10 +726,7 @@ module LocalFlow {
node2.asExpr() instanceof AssignExpr
)
or
exists(SsaImpl::Definition def |
def = getSsaDefinitionExt(node1) and
exists(SsaImpl::getAReadAtNode(def, node2.(ExprNode).getControlFlowNode()))
)
SsaFlow::localMustFlowStep(_, node1, node2)
or
node2 = node1.(LocalFunctionCreationNode).getAnAccess(true)
or
@@ -827,23 +750,14 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo, string model) {
(
LocalFlow::localFlowStepCommon(nodeFrom, nodeTo)
or
exists(SsaImpl::DefinitionExt def |
exists(SsaImpl::DefinitionExt def, boolean isUseStep |
SsaFlow::localFlowStep(def, nodeFrom, nodeTo, isUseStep) and
not LocalFlow::usesInstanceField(def) and
not def instanceof VariableCapture::CapturedSsaDefinitionExt
|
LocalFlow::localSsaFlowStep(def, nodeFrom, nodeTo)
isUseStep = false
or
LocalFlow::localSsaFlowStepUseUse(def, nodeFrom, nodeTo) and
not FlowSummaryImpl::Private::Steps::prohibitsUseUseFlow(nodeFrom, _) and
nodeFrom != nodeTo
or
// Flow into phi (read)/uncertain SSA definition node from read
exists(Node read | LocalFlow::localFlowSsaInputFromRead(read, def, nodeTo) |
nodeFrom = read and
not FlowSummaryImpl::Private::Steps::prohibitsUseUseFlow(nodeFrom, _)
or
nodeFrom.(PostUpdateNode).getPreUpdateNode() = read
)
not FlowSummaryImpl::Private::Steps::prohibitsUseUseFlow(nodeFrom, _)
)
or
nodeTo.(ObjectCreationNode).getPreUpdateNode() = nodeFrom.(ObjectInitializerNode)
@@ -1113,11 +1027,7 @@ private module Cached {
cached
newtype TNode =
TExprNode(ControlFlow::Nodes::ElementNode cfn) { cfn.getAstNode() instanceof Expr } or
TSsaDefinitionExtNode(SsaImpl::DefinitionExt def) {
// Handled by `TExplicitParameterNode` below
not def instanceof Ssa::ImplicitParameterDefinition and
def.getBasicBlock() = any(DataFlowCallable c).getAControlFlowNode().getBasicBlock()
} or
TSsaNode(SsaImpl::DataFlowIntegration::SsaNode node) or
TAssignableDefinitionNode(AssignableDefinition def, ControlFlow::Node cfn) {
cfn = def.getExpr().getAControlFlowNode()
} or
@@ -1180,17 +1090,7 @@ private module Cached {
predicate localFlowStepImpl(Node nodeFrom, Node nodeTo) {
LocalFlow::localFlowStepCommon(nodeFrom, nodeTo)
or
LocalFlow::localSsaFlowStepUseUse(_, nodeFrom, nodeTo) and
nodeFrom != nodeTo
or
LocalFlow::localSsaFlowStep(_, nodeFrom, nodeTo)
or
// Flow into phi (read)/uncertain SSA definition node from read
exists(Node read | LocalFlow::localFlowSsaInputFromRead(read, _, nodeTo) |
nodeFrom = read
or
nodeFrom.(PostUpdateNode).getPreUpdateNode() = read
)
SsaFlow::localFlowStep(_, nodeFrom, nodeTo, _)
or
// Simple flow through library code is included in the exposed local
// step relation, even though flow is technically inter-procedural
@@ -1254,7 +1154,7 @@ import Cached
/** Holds if `n` should be hidden from path explanations. */
predicate nodeIsHidden(Node n) {
n instanceof SsaDefinitionExtNode
n instanceof SsaNode
or
exists(Parameter p | p = n.(ParameterNode).getParameter() | not p.fromSource())
or
@@ -1288,13 +1188,16 @@ predicate nodeIsHidden(Node n) {
n instanceof CaptureNode
}
/** An SSA definition, viewed as a node in a data flow graph. */
class SsaDefinitionExtNode extends NodeImpl, TSsaDefinitionExtNode {
/** An SSA node. */
abstract class SsaNode extends NodeImpl, TSsaNode {
SsaImpl::DataFlowIntegration::SsaNode node;
SsaImpl::DefinitionExt def;
SsaDefinitionExtNode() { this = TSsaDefinitionExtNode(def) }
SsaNode() {
this = TSsaNode(node) and
def = node.getDefinitionExt()
}
/** Gets the underlying SSA definition. */
SsaImpl::DefinitionExt getDefinitionExt() { result = def }
override DataFlowCallable getEnclosingCallableImpl() {
@@ -1307,9 +1210,57 @@ class SsaDefinitionExtNode extends NodeImpl, TSsaDefinitionExtNode {
result = def.(Ssa::Definition).getControlFlowNode()
}
override Location getLocationImpl() { result = def.getLocation() }
override Location getLocationImpl() { result = node.getLocation() }
override string toStringImpl() { result = def.toString() }
override string toStringImpl() { result = node.toString() }
}
/** An (extended) SSA definition, viewed as a node in a data flow graph. */
class SsaDefinitionExtNode extends SsaNode {
override SsaImpl::DataFlowIntegration::SsaDefinitionExtNode node;
}
/**
* A node that represents an input to an SSA phi (read) definition.
*
* This allows for barrier guards to filter input to phi nodes. For example, in
*
* ```csharp
* var x = taint;
* if (x != "safe")
* {
* x = "safe";
* }
* sink(x);
* ```
*
* the `false` edge out of `x != "safe"` guards the input from `x = taint` into the
* `phi` node after the condition.
*
* It is also relevant to filter input into phi read nodes:
*
* ```csharp
* var x = taint;
* if (b)
* {
* if (x != "safe1")
* {
* return;
* }
* } else {
* if (x != "safe2")
* {
* return;
* }
* }
*
* sink(x);
* ```
*
* both inputs into the phi read node after the outer condition are guarded.
*/
class SsaInputNode extends SsaNode {
override SsaImpl::DataFlowIntegration::SsaInputNode node;
}
/** A definition, viewed as a node in a data flow graph. */
@@ -2907,7 +2858,7 @@ private predicate delegateCreationStep(Node nodeFrom, Node nodeTo) {
/** Extra data-flow steps needed for lambda flow analysis. */
predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preservesValue) {
exists(SsaImpl::DefinitionExt def |
LocalFlow::localSsaFlowStep(def, nodeFrom, nodeTo) and
SsaFlow::localFlowStep(def, nodeFrom, nodeTo, _) and
preservesValue = true
|
LocalFlow::usesInstanceField(def)

View File

@@ -171,8 +171,14 @@ signature predicate guardChecksSig(Guard g, Expr e, AbstractValue v);
* in data flow and taint tracking.
*/
module BarrierGuard<guardChecksSig/3 guardChecks> {
private import SsaImpl as SsaImpl
/** Gets a node that is safely guarded by the given guard check. */
ExprNode getABarrierNode() {
pragma[nomagic]
Node getABarrierNode() {
SsaFlow::asNode(result) =
SsaImpl::DataFlowIntegration::BarrierGuard<guardChecks/3>::getABarrierNode()
or
exists(Guard g, Expr e, AbstractValue v |
guardChecks(g, e, v) and
g.controlsNode(result.getControlFlowNode(), e, v)

View File

@@ -6,6 +6,7 @@ import csharp
private import codeql.ssa.Ssa as SsaImplCommon
private import AssignableDefinitions
private import semmle.code.csharp.controlflow.internal.PreSsa
private import semmle.code.csharp.controlflow.Guards as Guards
private module SsaInput implements SsaImplCommon::InputSig<Location> {
class BasicBlock = ControlFlow::BasicBlock;
@@ -49,7 +50,7 @@ private module SsaInput implements SsaImplCommon::InputSig<Location> {
}
}
private import SsaImplCommon::Make<Location, SsaInput> as Impl
import SsaImplCommon::Make<Location, SsaInput> as Impl
class Definition = Impl::Definition;
@@ -757,24 +758,6 @@ private predicate adjacentDefReachesRead(
)
}
private predicate adjacentDefReachesReadExt(
DefinitionExt def, SsaInput::SourceVariable v, SsaInput::BasicBlock bb1, int i1,
SsaInput::BasicBlock bb2, int i2
) {
Impl::adjacentDefReadExt(def, v, bb1, i1, bb2, i2) and
(
def.definesAt(v, bb1, i1, _)
or
SsaInput::variableRead(bb1, i1, v, true)
)
or
exists(SsaInput::BasicBlock bb3, int i3 |
adjacentDefReachesReadExt(def, v, bb1, i1, bb3, i3) and
SsaInput::variableRead(bb3, i3, v, false) and
Impl::adjacentDefReadExt(def, v, bb3, i3, bb2, i2)
)
}
/** Same as `adjacentDefRead`, but skips uncertain reads. */
pragma[nomagic]
private predicate adjacentDefSkipUncertainReads(
@@ -786,17 +769,6 @@ private predicate adjacentDefSkipUncertainReads(
)
}
/** Same as `adjacentDefReadExt`, but skips uncertain reads. */
pragma[nomagic]
private predicate adjacentDefSkipUncertainReadsExt(
DefinitionExt def, SsaInput::BasicBlock bb1, int i1, SsaInput::BasicBlock bb2, int i2
) {
exists(SsaInput::SourceVariable v |
adjacentDefReachesReadExt(def, v, bb1, i1, bb2, i2) and
SsaInput::variableRead(bb2, i2, v, true)
)
}
private predicate adjacentDefReachesUncertainRead(
Definition def, SsaInput::BasicBlock bb1, int i1, SsaInput::BasicBlock bb2, int i2
) {
@@ -806,16 +778,6 @@ private predicate adjacentDefReachesUncertainRead(
)
}
pragma[nomagic]
private predicate adjacentDefReachesUncertainReadExt(
DefinitionExt def, SsaInput::BasicBlock bb1, int i1, SsaInput::BasicBlock bb2, int i2
) {
exists(SsaInput::SourceVariable v |
adjacentDefReachesReadExt(def, v, bb1, i1, bb2, i2) and
SsaInput::variableRead(bb2, i2, v, false)
)
}
/** Same as `lastRefRedef`, but skips uncertain reads. */
pragma[nomagic]
private predicate lastRefSkipUncertainReads(Definition def, SsaInput::BasicBlock bb, int i) {
@@ -870,7 +832,7 @@ private module Cached {
predicate implicitEntryDefinition(ControlFlow::ControlFlow::BasicBlock bb, Ssa::SourceVariable v) {
exists(ControlFlow::ControlFlow::BasicBlocks::EntryBlock entry, Callable c |
c = entry.getCallable() and
// In case `c` has multiple bodies, we want each body to gets its own implicit
// In case `c` has multiple bodies, we want each body to get its own implicit
// entry definition. In case `c` doesn't have multiple bodies, the line below
// is simply the same as `bb = entry`, because `entry.getFirstNode().getASuccessor()`
// will be in the entry block.
@@ -965,19 +927,6 @@ private module Cached {
)
}
/**
* Holds if the value defined at SSA definition `def` can reach a read at `cfn`,
* without passing through any other read.
*/
cached
predicate firstReadSameVarExt(DefinitionExt def, ControlFlow::Node cfn) {
exists(ControlFlow::BasicBlock bb1, int i1, ControlFlow::BasicBlock bb2, int i2 |
def.definesAt(_, bb1, i1, _) and
adjacentDefSkipUncertainReadsExt(def, bb1, i1, bb2, i2) and
cfn = bb2.getNode(i2)
)
}
/**
* Holds if the read at `cfn2` is a read of the same SSA definition `def`
* as the read at `cfn1`, and `cfn2` can be reached from `cfn1` without
@@ -993,23 +942,6 @@ private module Cached {
)
}
/**
* Holds if the read at `cfn2` is a read of the same SSA definition `def`
* as the read at `cfn1`, and `cfn2` can be reached from `cfn1` without
* passing through another read.
*/
cached
predicate adjacentReadPairSameVarExt(
DefinitionExt def, ControlFlow::Node cfn1, ControlFlow::Node cfn2
) {
exists(ControlFlow::BasicBlock bb1, int i1, ControlFlow::BasicBlock bb2, int i2 |
cfn1 = bb1.getNode(i1) and
variableReadActual(bb1, i1, _) and
adjacentDefSkipUncertainReadsExt(def, bb1, i1, bb2, i2) and
cfn2 = bb2.getNode(i2)
)
}
cached
predicate lastRefBeforeRedef(Definition def, ControlFlow::BasicBlock bb, int i, Definition next) {
Impl::lastRefRedef(def, bb, i, next) and
@@ -1021,21 +953,6 @@ private module Cached {
)
}
cached
predicate lastRefBeforeRedefExt(
DefinitionExt def, ControlFlow::BasicBlock bb, int i, DefinitionExt next
) {
exists(SsaInput::SourceVariable v |
Impl::lastRefRedefExt(def, v, bb, i, next) and
not SsaInput::variableRead(bb, i, v, false)
)
or
exists(SsaInput::BasicBlock bb0, int i0 |
Impl::lastRefRedefExt(def, _, bb0, i0, next) and
adjacentDefReachesUncertainReadExt(def, bb, i, bb0, i0)
)
}
cached
predicate lastReadSameVar(Definition def, ControlFlow::Node cfn) {
exists(ControlFlow::BasicBlock bb, int i |
@@ -1061,6 +978,41 @@ private module Cached {
outRefExitRead(bb, i, v)
)
}
cached
module DataFlowIntegration {
import DataFlowIntegrationImpl
cached
predicate localFlowStep(DefinitionExt def, Node nodeFrom, Node nodeTo, boolean isUseStep) {
DataFlowIntegrationImpl::localFlowStep(def, nodeFrom, nodeTo, isUseStep)
}
cached
predicate localMustFlowStep(DefinitionExt def, Node nodeFrom, Node nodeTo) {
DataFlowIntegrationImpl::localMustFlowStep(def, nodeFrom, nodeTo)
}
signature predicate guardChecksSig(Guards::Guard g, Expr e, Guards::AbstractValue v);
cached // nothing is actually cached
module BarrierGuard<guardChecksSig/3 guardChecks> {
private predicate guardChecksAdjTypes(
DataFlowIntegrationInput::Guard g, DataFlowIntegrationInput::Expr e, boolean branch
) {
exists(Guards::AbstractValues::BooleanValue v |
guardChecks(g, e.getAstNode(), v) and
branch = v.getValue()
)
}
private Node getABarrierNodeImpl() {
result = DataFlowIntegrationImpl::BarrierGuard<guardChecksAdjTypes/3>::getABarrierNode()
}
predicate getABarrierNode = getABarrierNodeImpl/0;
}
}
}
import Cached
@@ -1118,3 +1070,64 @@ class PhiReadNode extends DefinitionExt, Impl::PhiReadNode {
result = this.getSourceVariable().getEnclosingCallable()
}
}
private module DataFlowIntegrationInput implements Impl::DataFlowIntegrationInputSig {
private import csharp as Cs
private import semmle.code.csharp.controlflow.BasicBlocks
class Expr extends ControlFlow::Node {
predicate hasCfgNode(ControlFlow::BasicBlock bb, int i) { this = bb.getNode(i) }
}
Expr getARead(Definition def) { exists(getAReadAtNode(def, result)) }
predicate ssaDefAssigns(WriteDefinition def, Expr value) {
// exclude flow directly from RHS to SSA definition, as we instead want to
// go from RHS to matching assingnable definition, and from there to SSA definition
none()
}
class Parameter = Ssa::ImplicitParameterDefinition;
predicate ssaDefInitializesParam(WriteDefinition def, Parameter p) { def = p }
/**
* Allows for flow into uncertain defintions that are not call definitions,
* as we, conservatively, consider such definitions to be certain.
*/
predicate allowFlowIntoUncertainDef(UncertainWriteDefinition def) {
def instanceof Ssa::ExplicitDefinition
or
def =
any(Ssa::ImplicitQualifierDefinition qdef |
allowFlowIntoUncertainDef(qdef.getQualifierDefinition())
)
}
class Guard extends Guards::Guard {
predicate hasCfgNode(ControlFlow::BasicBlock bb, int i) {
this.getAControlFlowNode() = bb.getNode(i)
}
}
/** Holds if the guard `guard` controls block `bb` upon evaluating to `branch`. */
predicate guardControlsBlock(Guard guard, ControlFlow::BasicBlock bb, boolean branch) {
exists(ConditionBlock conditionBlock, ControlFlow::SuccessorTypes::ConditionalSuccessor s |
guard.getAControlFlowNode() = conditionBlock.getLastNode() and
s.getValue() = branch and
conditionBlock.controls(bb, s)
)
}
/** Gets an immediate conditional successor of basic block `bb`, if any. */
ControlFlow::BasicBlock getAConditionalBasicBlockSuccessor(
ControlFlow::BasicBlock bb, boolean branch
) {
exists(ControlFlow::SuccessorTypes::ConditionalSuccessor s |
result = bb.getASuccessorByType(s) and
s.getValue() = branch
)
}
}
private module DataFlowIntegrationImpl = Impl::DataFlowIntegration<DataFlowIntegrationInput>;

View File

@@ -12,18 +12,21 @@
| CSharp7.cs:15:9:15:11 | SSA entry def(this.field) | CSharp7.cs:15:18:15:22 | access to field field |
| CSharp7.cs:15:9:15:11 | this | CSharp7.cs:15:18:15:22 | this access |
| CSharp7.cs:19:9:19:11 | this | CSharp7.cs:19:16:19:20 | this access |
| CSharp7.cs:20:9:20:11 | SSA param(value) | CSharp7.cs:20:24:20:28 | access to parameter value |
| CSharp7.cs:20:9:20:11 | this | CSharp7.cs:20:16:20:20 | this access |
| CSharp7.cs:20:9:20:11 | value | CSharp7.cs:20:24:20:28 | access to parameter value |
| CSharp7.cs:20:9:20:11 | value | CSharp7.cs:20:9:20:11 | SSA param(value) |
| CSharp7.cs:20:24:20:28 | access to parameter value | CSharp7.cs:20:16:20:20 | access to field field |
| CSharp7.cs:23:5:23:27 | this | CSharp7.cs:14:9:14:13 | this access |
| CSharp7.cs:24:6:24:28 | this | CSharp7.cs:24:35:24:39 | this access |
| CSharp7.cs:29:19:29:19 | i | CSharp7.cs:31:16:31:16 | access to parameter i |
| CSharp7.cs:29:19:29:19 | SSA param(i) | CSharp7.cs:31:16:31:16 | access to parameter i |
| CSharp7.cs:29:19:29:19 | i | CSharp7.cs:29:19:29:19 | SSA param(i) |
| CSharp7.cs:31:16:31:16 | access to parameter i | CSharp7.cs:31:16:31:20 | ... > ... |
| CSharp7.cs:31:16:31:16 | access to parameter i | CSharp7.cs:31:24:31:24 | access to parameter i |
| CSharp7.cs:31:24:31:24 | access to parameter i | CSharp7.cs:31:16:31:59 | ... ? ... : ... |
| CSharp7.cs:39:9:39:9 | access to parameter x | CSharp7.cs:39:9:39:21 | SSA def(x) |
| CSharp7.cs:39:13:39:21 | "tainted" | CSharp7.cs:39:9:39:9 | access to parameter x |
| CSharp7.cs:42:19:42:19 | x | CSharp7.cs:44:13:44:13 | access to parameter x |
| CSharp7.cs:42:19:42:19 | SSA param(x) | CSharp7.cs:44:13:44:13 | access to parameter x |
| CSharp7.cs:42:19:42:19 | x | CSharp7.cs:42:19:42:19 | SSA param(x) |
| CSharp7.cs:44:9:44:9 | access to parameter y | CSharp7.cs:44:9:44:13 | SSA def(y) |
| CSharp7.cs:44:13:44:13 | access to parameter x | CSharp7.cs:44:9:44:9 | access to parameter y |
| CSharp7.cs:47:10:47:10 | this | CSharp7.cs:49:9:49:24 | this access |
@@ -86,7 +89,8 @@
| CSharp7.cs:77:22:77:28 | (..., ...) | CSharp7.cs:77:9:77:18 | (..., ...) |
| CSharp7.cs:77:23:77:24 | "" | CSharp7.cs:77:9:77:28 | ... = ... |
| CSharp7.cs:77:27:77:27 | access to local variable x | CSharp7.cs:77:9:77:28 | ... = ... |
| CSharp7.cs:80:21:80:21 | x | CSharp7.cs:82:20:82:20 | access to parameter x |
| CSharp7.cs:80:21:80:21 | SSA param(x) | CSharp7.cs:82:20:82:20 | access to parameter x |
| CSharp7.cs:80:21:80:21 | x | CSharp7.cs:80:21:80:21 | SSA param(x) |
| CSharp7.cs:85:10:85:18 | this | CSharp7.cs:90:18:90:28 | this access |
| CSharp7.cs:87:13:87:14 | access to local variable t1 | CSharp7.cs:87:13:87:34 | SSA def(t1) |
| CSharp7.cs:87:13:87:34 | SSA def(t1) | CSharp7.cs:88:28:88:29 | access to local variable t1 |
@@ -133,40 +137,51 @@
| CSharp7.cs:121:28:121:36 | "DefUse3" | CSharp7.cs:121:22:121:24 | access to local variable m12 |
| CSharp7.cs:121:28:121:36 | "DefUse3" | CSharp7.cs:121:22:121:36 | ... = ... |
| CSharp7.cs:127:9:127:12 | this | CSharp7.cs:133:24:133:25 | this access |
| CSharp7.cs:129:20:129:20 | x | CSharp7.cs:129:32:129:32 | access to parameter x |
| CSharp7.cs:129:20:129:20 | SSA param(x) | CSharp7.cs:129:32:129:32 | access to parameter x |
| CSharp7.cs:129:20:129:20 | x | CSharp7.cs:129:20:129:20 | SSA param(x) |
| CSharp7.cs:129:32:129:32 | access to parameter x | CSharp7.cs:129:32:129:36 | ... + ... |
| CSharp7.cs:129:36:129:36 | 1 | CSharp7.cs:129:32:129:36 | ... + ... |
| CSharp7.cs:131:22:131:22 | t | CSharp7.cs:131:39:131:39 | access to parameter t |
| CSharp7.cs:131:22:131:22 | SSA param(t) | CSharp7.cs:131:39:131:39 | access to parameter t |
| CSharp7.cs:131:22:131:22 | t | CSharp7.cs:131:22:131:22 | SSA param(t) |
| CSharp7.cs:133:24:133:25 | delegate creation of type Func<Int32> | CSharp7.cs:133:19:133:20 | access to local variable f4 |
| CSharp7.cs:133:24:133:25 | this access | CSharp7.cs:154:16:154:17 | this access |
| CSharp7.cs:137:29:137:29 | x | CSharp7.cs:137:34:137:34 | access to parameter x |
| CSharp7.cs:137:29:137:29 | SSA param(x) | CSharp7.cs:137:34:137:34 | access to parameter x |
| CSharp7.cs:137:29:137:29 | x | CSharp7.cs:137:29:137:29 | SSA param(x) |
| CSharp7.cs:137:29:137:38 | (...) => ... | CSharp7.cs:137:24:137:25 | access to local variable f5 |
| CSharp7.cs:137:34:137:34 | access to parameter x | CSharp7.cs:137:34:137:38 | ... + ... |
| CSharp7.cs:137:38:137:38 | 1 | CSharp7.cs:137:34:137:38 | ... + ... |
| CSharp7.cs:139:20:139:20 | x | CSharp7.cs:139:26:139:26 | access to parameter x |
| CSharp7.cs:139:20:139:20 | SSA param(x) | CSharp7.cs:139:26:139:26 | access to parameter x |
| CSharp7.cs:139:20:139:20 | x | CSharp7.cs:139:20:139:20 | SSA param(x) |
| CSharp7.cs:139:26:139:26 | access to parameter x | CSharp7.cs:139:26:139:30 | ... > ... |
| CSharp7.cs:139:26:139:26 | access to parameter x | CSharp7.cs:139:41:139:41 | access to parameter x |
| CSharp7.cs:139:34:139:34 | 1 | CSharp7.cs:139:34:139:46 | ... + ... |
| CSharp7.cs:139:34:139:46 | ... + ... | CSharp7.cs:139:26:139:50 | ... ? ... : ... |
| CSharp7.cs:139:38:139:46 | call to local function f7 | CSharp7.cs:139:34:139:46 | ... + ... |
| CSharp7.cs:139:50:139:50 | 0 | CSharp7.cs:139:26:139:50 | ... ? ... : ... |
| CSharp7.cs:141:20:141:20 | x | CSharp7.cs:141:29:141:29 | access to parameter x |
| CSharp7.cs:145:24:145:24 | x | CSharp7.cs:145:33:145:33 | access to parameter x |
| CSharp7.cs:141:20:141:20 | SSA param(x) | CSharp7.cs:141:29:141:29 | access to parameter x |
| CSharp7.cs:141:20:141:20 | x | CSharp7.cs:141:20:141:20 | SSA param(x) |
| CSharp7.cs:145:24:145:24 | SSA param(x) | CSharp7.cs:145:33:145:33 | access to parameter x |
| CSharp7.cs:145:24:145:24 | x | CSharp7.cs:145:24:145:24 | SSA param(x) |
| CSharp7.cs:149:20:152:9 | (...) => ... | CSharp7.cs:149:16:149:16 | access to local variable a |
| CSharp7.cs:157:10:157:17 | this | CSharp7.cs:169:9:169:9 | this access |
| CSharp7.cs:160:18:160:18 | t | CSharp7.cs:160:24:160:24 | access to parameter t |
| CSharp7.cs:162:26:162:26 | u | CSharp7.cs:166:22:166:22 | access to parameter u |
| CSharp7.cs:160:18:160:18 | SSA param(t) | CSharp7.cs:160:24:160:24 | access to parameter t |
| CSharp7.cs:160:18:160:18 | t | CSharp7.cs:160:18:160:18 | SSA param(t) |
| CSharp7.cs:162:26:162:26 | SSA param(u) | CSharp7.cs:166:22:166:22 | access to parameter u |
| CSharp7.cs:162:26:162:26 | u | CSharp7.cs:162:26:162:26 | SSA param(u) |
| CSharp7.cs:165:13:165:16 | this access | CSharp7.cs:166:20:166:20 | this access |
| CSharp7.cs:169:9:169:9 | this access | CSharp7.cs:170:9:170:9 | this access |
| CSharp7.cs:173:10:173:19 | this | CSharp7.cs:180:21:180:21 | this access |
| CSharp7.cs:175:16:175:18 | access to local variable src | CSharp7.cs:175:16:175:30 | SSA def(src) |
| CSharp7.cs:175:16:175:30 | SSA def(src) | CSharp7.cs:180:23:180:25 | access to local variable src |
| CSharp7.cs:175:22:175:30 | "tainted" | CSharp7.cs:175:16:175:18 | access to local variable src |
| CSharp7.cs:176:25:176:25 | s | CSharp7.cs:176:33:176:33 | access to parameter s |
| CSharp7.cs:176:25:176:25 | SSA param(s) | CSharp7.cs:176:33:176:33 | access to parameter s |
| CSharp7.cs:176:25:176:25 | s | CSharp7.cs:176:25:176:25 | SSA param(s) |
| CSharp7.cs:176:31:176:34 | call to local function g | CSharp7.cs:176:31:176:39 | ... + ... |
| CSharp7.cs:176:38:176:39 | "" | CSharp7.cs:176:31:176:39 | ... + ... |
| CSharp7.cs:177:25:177:25 | s | CSharp7.cs:177:31:177:31 | access to parameter s |
| CSharp7.cs:178:25:178:25 | s | CSharp7.cs:178:37:178:37 | access to parameter s |
| CSharp7.cs:177:25:177:25 | SSA param(s) | CSharp7.cs:177:31:177:31 | access to parameter s |
| CSharp7.cs:177:25:177:25 | s | CSharp7.cs:177:25:177:25 | SSA param(s) |
| CSharp7.cs:178:25:178:25 | SSA param(s) | CSharp7.cs:178:37:178:37 | access to parameter s |
| CSharp7.cs:178:25:178:25 | s | CSharp7.cs:178:25:178:25 | SSA param(s) |
| CSharp7.cs:180:21:180:21 | this access | CSharp7.cs:181:21:181:21 | this access |
| CSharp7.cs:180:21:180:26 | call to local function f | CSharp7.cs:180:13:180:17 | access to local variable sink1 |
| CSharp7.cs:180:23:180:25 | [post] access to local variable src | CSharp7.cs:181:23:181:25 | access to local variable src |
@@ -205,8 +220,10 @@
| CSharp7.cs:198:26:198:35 | this access | CSharp7.cs:199:9:199:18 | this access |
| CSharp7.cs:198:33:198:34 | access to local variable r1 | CSharp7.cs:199:16:199:17 | access to local variable r1 |
| CSharp7.cs:199:22:199:22 | 3 | CSharp7.cs:199:9:199:22 | ... = ... |
| CSharp7.cs:202:24:202:24 | p | CSharp7.cs:205:20:205:20 | access to parameter p |
| CSharp7.cs:204:28:204:28 | q | CSharp7.cs:204:44:204:44 | access to parameter q |
| CSharp7.cs:202:24:202:24 | SSA param(p) | CSharp7.cs:205:20:205:20 | access to parameter p |
| CSharp7.cs:202:24:202:24 | p | CSharp7.cs:202:24:202:24 | SSA param(p) |
| CSharp7.cs:204:28:204:28 | SSA param(q) | CSharp7.cs:204:44:204:44 | access to parameter q |
| CSharp7.cs:204:28:204:28 | q | CSharp7.cs:204:28:204:28 | SSA param(q) |
| CSharp7.cs:215:9:215:9 | access to parameter x | CSharp7.cs:215:9:215:17 | SSA def(x) |
| CSharp7.cs:215:13:215:17 | false | CSharp7.cs:215:9:215:9 | access to parameter x |
| CSharp7.cs:219:10:219:13 | this | CSharp7.cs:221:13:221:20 | this access |
@@ -224,8 +241,8 @@
| CSharp7.cs:232:16:232:23 | SSA def(o) | CSharp7.cs:233:13:233:13 | access to local variable o |
| CSharp7.cs:232:20:232:23 | null | CSharp7.cs:232:16:232:16 | access to local variable o |
| CSharp7.cs:233:13:233:13 | access to local variable o | CSharp7.cs:233:18:233:23 | Int32 i1 |
| CSharp7.cs:233:13:233:13 | access to local variable o | CSharp7.cs:235:13:235:42 | [input] SSA phi read(o) |
| CSharp7.cs:233:13:233:13 | access to local variable o | CSharp7.cs:237:18:237:18 | access to local variable o |
| CSharp7.cs:233:13:233:13 | access to local variable o | CSharp7.cs:248:9:274:9 | SSA phi read(o) |
| CSharp7.cs:233:13:233:23 | [false] ... is ... | CSharp7.cs:233:13:233:33 | [false] ... && ... |
| CSharp7.cs:233:13:233:23 | [true] ... is ... | CSharp7.cs:233:13:233:33 | [false] ... && ... |
| CSharp7.cs:233:13:233:23 | [true] ... is ... | CSharp7.cs:233:13:233:33 | [true] ... && ... |
@@ -235,19 +252,25 @@
| CSharp7.cs:233:28:233:29 | access to local variable i1 | CSharp7.cs:235:38:235:39 | access to local variable i1 |
| CSharp7.cs:233:28:233:33 | ... > ... | CSharp7.cs:233:13:233:33 | [false] ... && ... |
| CSharp7.cs:233:28:233:33 | ... > ... | CSharp7.cs:233:13:233:33 | [true] ... && ... |
| CSharp7.cs:235:13:235:42 | [input] SSA phi read(o) | CSharp7.cs:248:9:274:9 | SSA phi read(o) |
| CSharp7.cs:235:33:235:36 | "int " | CSharp7.cs:235:31:235:41 | $"..." |
| CSharp7.cs:235:38:235:39 | access to local variable i1 | CSharp7.cs:235:31:235:41 | $"..." |
| CSharp7.cs:237:18:237:18 | access to local variable o | CSharp7.cs:237:23:237:31 | String s1 |
| CSharp7.cs:237:18:237:18 | access to local variable o | CSharp7.cs:239:13:239:45 | [input] SSA phi read(o) |
| CSharp7.cs:237:18:237:18 | access to local variable o | CSharp7.cs:241:18:241:18 | access to local variable o |
| CSharp7.cs:237:18:237:18 | access to local variable o | CSharp7.cs:248:9:274:9 | SSA phi read(o) |
| CSharp7.cs:237:23:237:31 | SSA def(s1) | CSharp7.cs:239:41:239:42 | access to local variable s1 |
| CSharp7.cs:237:23:237:31 | String s1 | CSharp7.cs:237:23:237:31 | SSA def(s1) |
| CSharp7.cs:239:13:239:45 | [input] SSA phi read(o) | CSharp7.cs:248:9:274:9 | SSA phi read(o) |
| CSharp7.cs:239:33:239:39 | "string " | CSharp7.cs:239:31:239:44 | $"..." |
| CSharp7.cs:239:41:239:42 | access to local variable s1 | CSharp7.cs:239:31:239:44 | $"..." |
| CSharp7.cs:241:18:241:18 | access to local variable o | CSharp7.cs:242:9:243:9 | [input] SSA phi read(o) |
| CSharp7.cs:241:18:241:18 | access to local variable o | CSharp7.cs:244:18:244:18 | access to local variable o |
| CSharp7.cs:241:18:241:18 | access to local variable o | CSharp7.cs:248:9:274:9 | SSA phi read(o) |
| CSharp7.cs:242:9:243:9 | [input] SSA phi read(o) | CSharp7.cs:248:9:274:9 | SSA phi read(o) |
| CSharp7.cs:244:18:244:18 | access to local variable o | CSharp7.cs:244:18:244:28 | [input] SSA phi read(o) |
| CSharp7.cs:244:18:244:18 | access to local variable o | CSharp7.cs:244:23:244:28 | Object v1 |
| CSharp7.cs:244:18:244:18 | access to local variable o | CSharp7.cs:248:9:274:9 | SSA phi read(o) |
| CSharp7.cs:244:18:244:18 | access to local variable o | CSharp7.cs:245:9:246:9 | [input] SSA phi read(o) |
| CSharp7.cs:244:18:244:28 | [input] SSA phi read(o) | CSharp7.cs:248:9:274:9 | SSA phi read(o) |
| CSharp7.cs:245:9:246:9 | [input] SSA phi read(o) | CSharp7.cs:248:9:274:9 | SSA phi read(o) |
| CSharp7.cs:248:9:274:9 | SSA phi read(o) | CSharp7.cs:248:17:248:17 | access to local variable o |
| CSharp7.cs:248:17:248:17 | access to local variable o | CSharp7.cs:254:27:254:27 | access to local variable o |
| CSharp7.cs:248:17:248:17 | access to local variable o | CSharp7.cs:257:18:257:23 | Int32 i2 |
@@ -281,14 +304,16 @@
| CSharp7.cs:283:13:283:16 | access to local variable list | CSharp7.cs:283:13:283:62 | SSA def(list) |
| CSharp7.cs:283:13:283:62 | SSA def(list) | CSharp7.cs:285:39:285:42 | access to local variable list |
| CSharp7.cs:283:20:283:62 | call to method Select<KeyValuePair<Int32,String>,(Int32,String)> | CSharp7.cs:283:13:283:16 | access to local variable list |
| CSharp7.cs:283:32:283:35 | item | CSharp7.cs:283:41:283:44 | access to parameter item |
| CSharp7.cs:283:32:283:35 | SSA param(item) | CSharp7.cs:283:41:283:44 | access to parameter item |
| CSharp7.cs:283:32:283:35 | item | CSharp7.cs:283:32:283:35 | SSA param(item) |
| CSharp7.cs:283:41:283:44 | access to parameter item | CSharp7.cs:283:41:283:48 | access to property Key |
| CSharp7.cs:283:41:283:44 | access to parameter item | CSharp7.cs:283:51:283:54 | access to parameter item |
| CSharp7.cs:283:51:283:54 | access to parameter item | CSharp7.cs:283:51:283:60 | access to property Value |
| CSharp7.cs:285:39:285:42 | access to local variable list | CSharp7.cs:287:36:287:39 | access to local variable list |
| CSharp7.cs:287:36:287:39 | access to local variable list | CSharp7.cs:289:32:289:35 | access to local variable list |
| CSharp7.cs:297:18:297:18 | access to local variable x | CSharp7.cs:297:18:297:22 | SSA def(x) |
| CSharp7.cs:297:18:297:22 | SSA def(x) | CSharp7.cs:297:25:297:25 | SSA phi(x) |
| CSharp7.cs:297:18:297:22 | SSA def(x) | CSharp7.cs:297:18:297:22 | [input] SSA phi(x) |
| CSharp7.cs:297:18:297:22 | [input] SSA phi(x) | CSharp7.cs:297:25:297:25 | SSA phi(x) |
| CSharp7.cs:297:22:297:22 | 0 | CSharp7.cs:297:18:297:18 | access to local variable x |
| CSharp7.cs:297:25:297:25 | SSA phi(x) | CSharp7.cs:297:25:297:25 | access to local variable x |
| CSharp7.cs:297:25:297:25 | access to local variable x | CSharp7.cs:297:25:297:30 | ... < ... |
@@ -301,5 +326,6 @@
| CSharp7.cs:297:35:297:44 | [true] ... is ... | CSharp7.cs:297:25:297:44 | [true] ... && ... |
| CSharp7.cs:297:40:297:44 | Int32 y | CSharp7.cs:297:40:297:44 | SSA def(y) |
| CSharp7.cs:297:40:297:44 | SSA def(y) | CSharp7.cs:299:31:299:31 | access to local variable y |
| CSharp7.cs:297:47:297:49 | SSA def(x) | CSharp7.cs:297:25:297:25 | SSA phi(x) |
| CSharp7.cs:297:47:297:49 | SSA def(x) | CSharp7.cs:297:47:297:49 | [input] SSA phi(x) |
| CSharp7.cs:297:47:297:49 | [input] SSA phi(x) | CSharp7.cs:297:25:297:25 | SSA phi(x) |
| CSharp7.cs:297:49:297:49 | access to local variable x | CSharp7.cs:297:47:297:49 | SSA def(x) |

View File

@@ -0,0 +1,83 @@
class BarrierFlow
{
static object Source(object source) => throw null;
public static void Sink(object o) { }
void M1()
{
var x = Source(1);
Sink(x); // $ hasValueFlow=1
}
void M2()
{
var x = Source(2);
if (x != "safe")
{
Sink(x); // $ hasValueFlow=2
}
}
void M3()
{
var x = Source(3);
if (x == "safe")
{
Sink(x);
}
}
void M4()
{
var x = Source(4);
if (x != "safe")
{
x = "safe";
}
Sink(x);
}
void M5()
{
var x = Source(5);
if (x == "safe")
{
}
else
{
x = "safe";
}
Sink(x);
}
void M6(bool b)
{
var x = Source(6);
if (b)
{
if (x != "safe1")
{
return;
}
}
else
{
if (x != "safe2")
{
return;
}
}
Sink(x);
}
}

View File

@@ -0,0 +1,18 @@
models
edges
| BarrierFlow.cs:10:13:10:13 | access to local variable x : Object | BarrierFlow.cs:12:14:12:14 | access to local variable x | provenance | |
| BarrierFlow.cs:10:17:10:25 | call to method Source : Object | BarrierFlow.cs:10:13:10:13 | access to local variable x : Object | provenance | |
| BarrierFlow.cs:17:13:17:13 | access to local variable x : Object | BarrierFlow.cs:21:18:21:18 | access to local variable x | provenance | |
| BarrierFlow.cs:17:17:17:25 | call to method Source : Object | BarrierFlow.cs:17:13:17:13 | access to local variable x : Object | provenance | |
nodes
| BarrierFlow.cs:10:13:10:13 | access to local variable x : Object | semmle.label | access to local variable x : Object |
| BarrierFlow.cs:10:17:10:25 | call to method Source : Object | semmle.label | call to method Source : Object |
| BarrierFlow.cs:12:14:12:14 | access to local variable x | semmle.label | access to local variable x |
| BarrierFlow.cs:17:13:17:13 | access to local variable x : Object | semmle.label | access to local variable x : Object |
| BarrierFlow.cs:17:17:17:25 | call to method Source : Object | semmle.label | call to method Source : Object |
| BarrierFlow.cs:21:18:21:18 | access to local variable x | semmle.label | access to local variable x |
subpaths
testFailures
#select
| BarrierFlow.cs:12:14:12:14 | access to local variable x | BarrierFlow.cs:10:17:10:25 | call to method Source : Object | BarrierFlow.cs:12:14:12:14 | access to local variable x | $@ | BarrierFlow.cs:10:17:10:25 | call to method Source : Object | call to method Source : Object |
| BarrierFlow.cs:21:18:21:18 | access to local variable x | BarrierFlow.cs:17:17:17:25 | call to method Source : Object | BarrierFlow.cs:21:18:21:18 | access to local variable x | $@ | BarrierFlow.cs:17:17:17:25 | call to method Source : Object | call to method Source : Object |

View File

@@ -0,0 +1,35 @@
/**
* @kind path-problem
*/
import csharp
import semmle.code.csharp.controlflow.Guards
private predicate stringConstCompare(Guard guard, Expr testedNode, AbstractValue value) {
guard
.isEquality(any(StringLiteral lit), testedNode,
value.(AbstractValues::BooleanValue).getValue())
}
class StringConstCompareBarrier extends DataFlow::Node {
StringConstCompareBarrier() {
this = DataFlow::BarrierGuard<stringConstCompare/3>::getABarrierNode()
}
}
import TestUtilities.InlineFlowTest
import PathGraph
module FlowConfig implements DataFlow::ConfigSig {
predicate isSource = DefaultFlowConfig::isSource/1;
predicate isSink = DefaultFlowConfig::isSink/1;
predicate isBarrier(DataFlow::Node n) { n instanceof StringConstCompareBarrier }
}
import ValueFlowTest<FlowConfig>
from PathNode source, PathNode sink
where flowPath(source, sink)
select sink, source, sink, "$@", source, source.toString()

View File

@@ -92,7 +92,8 @@
| Tuples.cs:51:14:51:14 | [post] access to local variable y | Tuples.cs:52:14:52:14 | access to local variable y |
| Tuples.cs:51:14:51:14 | access to local variable y | Tuples.cs:52:14:52:14 | access to local variable y |
| Tuples.cs:52:14:52:20 | access to field Item2 | Tuples.cs:52:14:52:20 | (...) ... |
| Tuples.cs:55:27:55:27 | s | Tuples.cs:75:18:75:18 | access to parameter s |
| Tuples.cs:55:27:55:27 | SSA param(s) | Tuples.cs:75:18:75:18 | access to parameter s |
| Tuples.cs:55:27:55:27 | s | Tuples.cs:55:27:55:27 | SSA param(s) |
| Tuples.cs:57:13:57:14 | access to local variable o1 | Tuples.cs:57:13:57:34 | SSA def(o1) |
| Tuples.cs:57:13:57:34 | SSA def(o1) | Tuples.cs:59:18:59:19 | access to local variable o1 |
| Tuples.cs:57:18:57:34 | call to method Source<String> | Tuples.cs:57:13:57:14 | access to local variable o1 |