Skip to content

Commit fdd787b

Browse files
authored
Merge pull request github#7658 from hvitved/csharp/dataflow/no-negative-positions
C#: Get rid of negative parameter/argument data-flow positions
2 parents 8d1e22b + cbea5ea commit fdd787b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+3330
-3298
lines changed

csharp/ql/lib/semmle/code/csharp/dataflow/FlowSummary.qll

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,12 @@ module SummaryComponent {
4040
predicate return = SummaryComponentInternal::return/1;
4141

4242
/** Gets a summary component that represents a qualifier. */
43-
SummaryComponent qualifier() { result = argument(-1) }
43+
SummaryComponent qualifier() {
44+
exists(ParameterPosition pos |
45+
result = SummaryComponentInternal::argument(pos) and
46+
pos.isThisParameter()
47+
)
48+
}
4449

4550
/** Gets a summary component that represents an element in a collection. */
4651
SummaryComponent element() { result = content(any(DataFlow::ElementContent c)) }
@@ -140,12 +145,17 @@ private class SummarizedCallableDefaultClearsContent extends Impl::Public::Summa
140145

141146
// By default, we assume that all stores into arguments are definite
142147
override predicate clearsContent(ParameterPosition pos, DataFlow::Content content) {
143-
exists(SummaryComponentStack output |
148+
exists(SummaryComponentStack output, SummaryComponent target |
144149
this.propagatesFlow(_, output, _) and
145150
output.drop(_) =
146151
SummaryComponentStack::push(SummaryComponent::content(content),
147-
SummaryComponentStack::argument(pos.getPosition())) and
152+
SummaryComponentStack::singleton(target)) and
148153
not content instanceof DataFlow::ElementContent
154+
|
155+
target = SummaryComponent::argument(pos.getPosition())
156+
or
157+
target = SummaryComponent::qualifier() and
158+
pos.isThisParameter()
149159
)
150160
}
151161
}

csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll

Lines changed: 59 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -116,19 +116,23 @@ private module Cached {
116116
cached
117117
DataFlowCallable viableCallable(DataFlowCall call) { result = call.getARuntimeTarget() }
118118

119-
private int parameterPosition() {
120-
result =
121-
[
122-
-1, any(Parameter p).getPosition(),
123-
ImplicitCapturedParameterNodeImpl::getParameterPosition(_)
124-
]
119+
private predicate capturedWithFlowIn(LocalScopeVariable v) {
120+
exists(Ssa::ExplicitDefinition def | def.isCapturedVariableDefinitionFlowIn(_, _, _) |
121+
v = def.getSourceVariable().getAssignable()
122+
)
125123
}
126124

127125
cached
128-
newtype TParameterPosition = MkParameterPosition(int i) { i = parameterPosition() }
126+
newtype TParameterPosition =
127+
TPositionalParameterPosition(int i) { i = any(Parameter p).getPosition() } or
128+
TThisParameterPosition() or
129+
TImplicitCapturedParameterPosition(LocalScopeVariable v) { capturedWithFlowIn(v) }
129130

130131
cached
131-
newtype TArgumentPosition = MkArgumentPosition(int i) { i = parameterPosition() }
132+
newtype TArgumentPosition =
133+
TPositionalArgumentPosition(int i) { i = any(Parameter p).getPosition() } or
134+
TQualifierArgumentPosition() or
135+
TImplicitCapturedArgumentPosition(LocalScopeVariable v) { capturedWithFlowIn(v) }
132136
}
133137

134138
import Cached
@@ -268,8 +272,8 @@ abstract class DataFlowCall extends TDataFlowCall {
268272
/** Gets the underlying expression, if any. */
269273
final DotNet::Expr getExpr() { result = this.getNode().asExpr() }
270274

271-
/** Gets the `i`th argument of this call. */
272-
final ArgumentNode getArgument(int i) { result.argumentOf(this, i) }
275+
/** Gets the argument at position `pos` of this call. */
276+
final ArgumentNode getArgument(ArgumentPosition pos) { result.argumentOf(this, pos) }
273277

274278
/** Gets a textual representation of this call. */
275279
abstract string toString();
@@ -425,36 +429,64 @@ class SummaryCall extends DelegateDataFlowCall, TSummaryCall {
425429
override Location getLocation() { result = c.getLocation() }
426430
}
427431

428-
/** A parameter position represented by an integer. */
429-
class ParameterPosition extends MkParameterPosition {
430-
private int i;
432+
/** A parameter position. */
433+
class ParameterPosition extends TParameterPosition {
434+
/** Gets the underlying integer position, if any. */
435+
int getPosition() { this = TPositionalParameterPosition(result) }
431436

432-
ParameterPosition() { this = MkParameterPosition(i) }
437+
/** Holds if this position represents a `this` parameter. */
438+
predicate isThisParameter() { this = TThisParameterPosition() }
433439

434-
/** Gets the underlying integer. */
435-
int getPosition() { result = i }
440+
/** Holds if this position is used to model flow through captured variables. */
441+
predicate isImplicitCapturedParameterPosition(LocalScopeVariable v) {
442+
this = TImplicitCapturedParameterPosition(v)
443+
}
436444

437445
/** Gets a textual representation of this position. */
438-
string toString() { result = i.toString() }
446+
string toString() {
447+
result = "position " + this.getPosition()
448+
or
449+
this.isThisParameter() and result = "this"
450+
or
451+
exists(LocalScopeVariable v |
452+
this.isImplicitCapturedParameterPosition(v) and result = "captured " + v
453+
)
454+
}
439455
}
440456

441-
/** An argument position represented by an integer. */
442-
class ArgumentPosition extends MkArgumentPosition {
443-
private int i;
457+
/** An argument position. */
458+
class ArgumentPosition extends TArgumentPosition {
459+
/** Gets the underlying integer position, if any. */
460+
int getPosition() { this = TPositionalArgumentPosition(result) }
444461

445-
ArgumentPosition() { this = MkArgumentPosition(i) }
462+
/** Holds if this position represents a qualifier. */
463+
predicate isQualifier() { this = TQualifierArgumentPosition() }
446464

447-
/** Gets the underlying integer. */
448-
int getPosition() { result = i }
465+
/** Holds if this position is used to model flow through captured variables. */
466+
predicate isImplicitCapturedArgumentPosition(LocalScopeVariable v) {
467+
this = TImplicitCapturedArgumentPosition(v)
468+
}
449469

450470
/** Gets a textual representation of this position. */
451-
string toString() { result = i.toString() }
471+
string toString() {
472+
result = "position " + this.getPosition()
473+
or
474+
this.isQualifier() and result = "qualifier"
475+
or
476+
exists(LocalScopeVariable v |
477+
this.isImplicitCapturedArgumentPosition(v) and result = "captured " + v
478+
)
479+
}
452480
}
453481

454482
/** Holds if arguments at position `apos` match parameters at position `ppos`. */
455483
predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) {
456-
exists(int i |
457-
ppos = MkParameterPosition(i) and
458-
apos = MkArgumentPosition(i)
484+
ppos.getPosition() = apos.getPosition()
485+
or
486+
ppos.isThisParameter() and apos.isQualifier()
487+
or
488+
exists(LocalScopeVariable v |
489+
ppos.isImplicitCapturedParameterPosition(v) and
490+
apos.isImplicitCapturedArgumentPosition(v)
459491
)
460492
}

0 commit comments

Comments
 (0)