Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
hvitved committed Jun 25, 2024
1 parent 86c093e commit 187a1bb
Show file tree
Hide file tree
Showing 9 changed files with 221 additions and 92 deletions.
24 changes: 19 additions & 5 deletions csharp/ql/lib/semmle/code/csharp/dataflow/SSA.qll
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,21 @@ import csharp
module Ssa {
private import internal.SsaImpl as SsaImpl

pragma[nomagic]
private predicate assignableDefinitionLocalVariable(
AssignableDefinition ad, LocalScopeVariable v, Callable c
) {
ad.getTarget() = v and
ad.getEnclosingCallable() = c
}

private predicate localSourceVariable(
SourceVariables::LocalScopeSourceVariable sv, LocalScopeVariable v, Callable c
) {
sv.getAssignable() = v and
sv.getEnclosingCallable() = c
}

/**
* A variable that can be SSA converted.
*
Expand All @@ -34,11 +49,10 @@ module Ssa {
or
// Local variable declaration without initializer
not exists(result.getTargetAccess()) and
this =
any(SourceVariables::LocalScopeSourceVariable v |
result.getTarget() = v.getAssignable() and
result.getEnclosingCallable() = v.getEnclosingCallable()
)
exists(LocalScopeVariable v, Callable c |
assignableDefinitionLocalVariable(result, v, c) and
localSourceVariable(this, v, c)
)
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,10 @@ private module Cached {
*/
cached
newtype TDataFlowCallable =
TCallable(Callable c) { c.isUnboundDeclaration() } or
TCallable(Callable c, Location l) {
c.isUnboundDeclaration() and
l = [c.getLocation(), c.getALocation().(SourceLocation)]
} or
TSummarizedCallable(FlowSummary::SummarizedCallable sc) or
TFieldOrPropertyCallable(FieldOrProperty f) or
TCapturedVariableCallable(LocalScopeVariable v) { v.isCaptured() }
Expand Down Expand Up @@ -88,7 +91,8 @@ private module DispatchImpl {
*/
DataFlowCallable viableImplInCallContext(DataFlowCall call, DataFlowCall ctx) {
exists(DispatchCall dc | dc = call.(NonDelegateDataFlowCall).getDispatchCall() |
result.getUnderlyingCallable() =
result.asCallable(_) =
// todo
getCallableForDataFlow(dc.getADynamicTargetInCallContext(ctx.(NonDelegateDataFlowCall)
.getDispatchCall()).getUnboundDeclaration())
or
Expand Down Expand Up @@ -156,10 +160,21 @@ class RefReturnKind extends OutRefReturnKind, TRefReturnKind {
override string toString() { result = "ref parameter " + pos }
}

bindingset[e1, e2]
pragma[inline_late]
private predicate inSameFile(Location e1, Location e2) { e1.getFile() = e2.getFile() }

/** A callable used for data flow. */
class DataFlowCallable extends TDataFlowCallable {
/** Gets the underlying source code callable, if any. */
Callable asCallable() { this = TCallable(result) }
Callable asCallable(Location l) { this = TCallable(result, l) }

ControlFlow::BasicBlock getABasicBlock() {
exists(Location l |
result.getCallable() = this.asCallable(l) and
inSameFile(result.getLocation(), l)
)
}

/** Gets the underlying summarized callable, if any. */
FlowSummary::SummarizedCallable asSummarizedCallable() { this = TSummarizedCallable(result) }
Expand All @@ -171,7 +186,7 @@ class DataFlowCallable extends TDataFlowCallable {

/** Gets the underlying callable. */
Callable getUnderlyingCallable() {
result = this.asCallable() or result = this.asSummarizedCallable()
result = this.asCallable(_) or result = this.asSummarizedCallable()
}

/** Gets a textual representation of this dataflow callable. */
Expand All @@ -185,7 +200,9 @@ class DataFlowCallable extends TDataFlowCallable {

/** Get the location of this dataflow callable. */
Location getLocation() {
result = this.getUnderlyingCallable().getLocation()
this = TCallable(_, result)
or
result = this.asSummarizedCallable().getLocation()
or
result = this.asFieldOrProperty().getLocation()
or
Expand Down Expand Up @@ -256,6 +273,25 @@ abstract class DataFlowCall extends TDataFlowCall {
}
}

private predicate relevantFolder(Folder f) {
exists(NonDelegateDataFlowCall call, Location l | f = l.getFile().getParentContainer() |
l = call.getLocation()
or
exists(call.getARuntimeTargetCandidate(l, _))
)
}

private predicate parent(Folder f1, Folder f2) {
f1 = f2.getParentContainer()
or
f2 = f1.getParentContainer()
}

bindingset[f1, f2]
pragma[inline_late]
private predicate folderDist(Folder f1, Folder f2, int i) =
shortestDistances(relevantFolder/1, parent/2)(f1, f2, i)

/** A non-delegate C# call relevant for data flow. */
class NonDelegateDataFlowCall extends DataFlowCall, TNonDelegateCall {
private ControlFlow::Nodes::ElementNode cfn;
Expand All @@ -266,25 +302,57 @@ class NonDelegateDataFlowCall extends DataFlowCall, TNonDelegateCall {
/** Gets the underlying call. */
DispatchCall getDispatchCall() { result = dc }

override DataFlowCallable getARuntimeTarget() {
result.asCallable() = getCallableForDataFlow(dc.getADynamicTarget())
or
pragma[nomagic]
DataFlowCallable getARuntimeTargetCandidate(Location l, Callable c) {
c = result.asCallable(l) and
c = getCallableForDataFlow(dc.getADynamicTarget())
}

pragma[nomagic]
private DataFlowCallable getARuntimeTargetCandidateAtDist(int dist, Callable c) {
exists(Location l | result = this.getARuntimeTargetCandidate(l, c) |
inSameFile(l, this.getLocation()) and
dist = -1
or
folderDist(l.getFile().getParentContainer(),
this.getLocation().getFile().getParentContainer(), dist)
)
}

pragma[nomagic]
private predicate hasSourceTarget() { dc.getADynamicTarget().fromSource() }

pragma[nomagic]
private FlowSummary::SummarizedCallable getASummarizedCallableTarget() {
// Only use summarized callables with generated summaries in case
// we are not able to dispatch to a source declaration.
exists(FlowSummary::SummarizedCallable sc, boolean static |
result.asSummarizedCallable() = sc and
sc = this.getATarget(static) and
exists(boolean static |
result = this.getATarget(static) and
not (
sc.applyGeneratedModel() and
dc.getADynamicTarget().getUnboundDeclaration().getFile().fromSource()
result.applyGeneratedModel() and
this.hasSourceTarget()
)
|
static = false
or
static = true and not sc instanceof RuntimeCallable
static = true and not result instanceof RuntimeCallable
)
}

pragma[nomagic]
override DataFlowCallable getARuntimeTarget() {
exists(Callable c |
result =
min(DataFlowCallable cand, int dist |
cand = this.getARuntimeTargetCandidateAtDist(dist, c)
|
cand order by dist
)
)
or
result.asSummarizedCallable() = this.getASummarizedCallableTarget()
}

/** Gets a static or dynamic target of this call. */
Callable getATarget(boolean static) {
result = dc.getADynamicTarget().getUnboundDeclaration() and static = false
Expand All @@ -296,9 +364,7 @@ class NonDelegateDataFlowCall extends DataFlowCall, TNonDelegateCall {

override DataFlow::ExprNode getNode() { result.getControlFlowNode() = cfn }

override DataFlowCallable getEnclosingCallable() {
result.asCallable() = cfn.getEnclosingCallable()
}
override DataFlowCallable getEnclosingCallable() { result.getABasicBlock() = cfn.getBasicBlock() }

override string toString() { result = cfn.toString() }

Expand Down Expand Up @@ -326,9 +392,7 @@ class ExplicitDelegateLikeDataFlowCall extends DelegateDataFlowCall, TExplicitDe

override DataFlow::ExprNode getNode() { result.getControlFlowNode() = cfn }

override DataFlowCallable getEnclosingCallable() {
result.asCallable() = cfn.getEnclosingCallable()
}
override DataFlowCallable getEnclosingCallable() { result.getABasicBlock() = cfn.getBasicBlock() }

override string toString() { result = cfn.toString() }

Expand Down
Loading

0 comments on commit 187a1bb

Please sign in to comment.