Skip to content

Commit 0990a1b

Browse files
committed
C#: Get rid of negative parameter/argument data-flow positions
1 parent 3df3054 commit 0990a1b

File tree

6 files changed

+152
-106
lines changed

6 files changed

+152
-106
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: 55 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -116,19 +116,17 @@ 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-
]
125-
}
126-
127119
cached
128-
newtype TParameterPosition = MkParameterPosition(int i) { i = parameterPosition() }
120+
newtype TParameterPosition =
121+
TPositionalParameterPosition(int i) { i = any(Parameter p).getPosition() } or
122+
TThisParameterPosition() or
123+
TImplicitCapturedParameterPosition(SsaCapturedEntryDefinition def)
129124

130125
cached
131-
newtype TArgumentPosition = MkArgumentPosition(int i) { i = parameterPosition() }
126+
newtype TArgumentPosition =
127+
TPositionalArgumentPosition(int i) { i = any(Parameter p).getPosition() } or
128+
TQualifierArgumentPosition() or
129+
TImplicitCapturedArgumentPosition(SsaCapturedEntryDefinition def)
132130
}
133131

134132
import Cached
@@ -268,8 +266,8 @@ abstract class DataFlowCall extends TDataFlowCall {
268266
/** Gets the underlying expression, if any. */
269267
final DotNet::Expr getExpr() { result = this.getNode().asExpr() }
270268

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

274272
/** Gets a textual representation of this call. */
275273
abstract string toString();
@@ -425,36 +423,64 @@ class SummaryCall extends DelegateDataFlowCall, TSummaryCall {
425423
override Location getLocation() { result = c.getLocation() }
426424
}
427425

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

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

434-
/** Gets the underlying integer. */
435-
int getPosition() { result = i }
434+
/** Holds if this position is used to model flow through captured variables. */
435+
predicate isImplicitCapturedParameterPosition(SsaCapturedEntryDefinition def) {
436+
this = TImplicitCapturedParameterPosition(def)
437+
}
436438

437439
/** Gets a textual representation of this position. */
438-
string toString() { result = i.toString() }
440+
string toString() {
441+
result = "position " + this.getPosition()
442+
or
443+
this.isThisParameter() and result = "this"
444+
or
445+
exists(SsaCapturedEntryDefinition def |
446+
this.isImplicitCapturedParameterPosition(def) and result = "captured " + def
447+
)
448+
}
439449
}
440450

441-
/** An argument position represented by an integer. */
442-
class ArgumentPosition extends MkArgumentPosition {
443-
private int i;
451+
/** An argument position. */
452+
class ArgumentPosition extends TArgumentPosition {
453+
/** Gets the underlying integer position, if any. */
454+
int getPosition() { this = TPositionalArgumentPosition(result) }
444455

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

447-
/** Gets the underlying integer. */
448-
int getPosition() { result = i }
459+
/** Holds if this position is used to model flow through captured variables. */
460+
predicate isImplicitCapturedArgumentPosition(SsaCapturedEntryDefinition def) {
461+
this = TImplicitCapturedArgumentPosition(def)
462+
}
449463

450464
/** Gets a textual representation of this position. */
451-
string toString() { result = i.toString() }
465+
string toString() {
466+
result = "position " + this.getPosition()
467+
or
468+
this.isQualifier() and result = "qualifier"
469+
or
470+
exists(SsaCapturedEntryDefinition def |
471+
this.isImplicitCapturedArgumentPosition(def) and result = "captured " + def
472+
)
473+
}
452474
}
453475

454476
/** Holds if arguments at position `apos` match parameters at position `ppos`. */
455477
predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) {
456-
exists(int i |
457-
ppos = MkParameterPosition(i) and
458-
apos = MkArgumentPosition(i)
478+
ppos.getPosition() = apos.getPosition()
479+
or
480+
ppos.isThisParameter() and apos.isQualifier()
481+
or
482+
exists(SsaCapturedEntryDefinition def |
483+
ppos.isImplicitCapturedParameterPosition(def) and
484+
apos.isImplicitCapturedArgumentPosition(def)
459485
)
460486
}

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

Lines changed: 46 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,13 @@ private import semmle.code.csharp.frameworks.system.threading.Tasks
2222
DataFlowCallable nodeGetEnclosingCallable(Node n) { result = n.getEnclosingCallable() }
2323

2424
/** Holds if `p` is a `ParameterNode` of `c` with position `pos`. */
25-
predicate isParameterNode(ParameterNode p, DataFlowCallable c, ParameterPosition pos) {
26-
exists(int i | pos = MkParameterPosition(i) and p.isParameterOf(c, i))
25+
predicate isParameterNode(ParameterNodeImpl p, DataFlowCallable c, ParameterPosition pos) {
26+
p.isParameterOf(c, pos)
2727
}
2828

2929
/** Holds if `arg` is an `ArgumentNode` of `c` with position `pos`. */
3030
predicate isArgumentNode(ArgumentNode arg, DataFlowCall c, ArgumentPosition pos) {
31-
exists(int i | pos = MkArgumentPosition(i) and arg.argumentOf(c, i))
31+
arg.argumentOf(c, pos)
3232
}
3333

3434
abstract class NodeImpl extends Node {
@@ -469,26 +469,28 @@ private predicate isParamsArg(Call c, Expr arg, Parameter p) {
469469
/** An argument of a C# call (including qualifier arguments). */
470470
private class Argument extends Expr {
471471
private Expr call;
472-
private int arg;
472+
private ArgumentPosition arg;
473473

474474
Argument() {
475475
call =
476476
any(DispatchCall dc |
477-
this = dc.getArgument(arg) and
477+
this = dc.getArgument(arg.getPosition()) and
478478
not isParamsArg(_, this, _)
479479
or
480-
this = dc.getQualifier() and arg = -1 and not dc.getAStaticTarget().(Modifiable).isStatic()
480+
this = dc.getQualifier() and
481+
arg.isQualifier() and
482+
not dc.getAStaticTarget().(Modifiable).isStatic()
481483
).getCall()
482484
or
483-
this = call.(DelegateLikeCall).getArgument(arg)
485+
this = call.(DelegateLikeCall).getArgument(arg.getPosition())
484486
}
485487

486488
/**
487489
* Holds if this expression is the `i`th argument of `c`.
488490
*
489491
* Qualifier arguments have index `-1`.
490492
*/
491-
predicate isArgumentOf(Expr c, int i) { c = call and i = arg }
493+
predicate isArgumentOf(Expr c, ArgumentPosition pos) { c = call and pos = arg }
492494
}
493495

494496
/**
@@ -855,7 +857,7 @@ class SsaDefinitionNode extends NodeImpl, TSsaDefinitionNode {
855857
}
856858

857859
abstract class ParameterNodeImpl extends NodeImpl {
858-
abstract predicate isParameterOf(DataFlowCallable c, int i);
860+
abstract predicate isParameterOf(DataFlowCallable c, ParameterPosition pos);
859861
}
860862

861863
private module ParameterNodes {
@@ -874,7 +876,9 @@ private module ParameterNodes {
874876
parameter
875877
}
876878

877-
override predicate isParameterOf(DataFlowCallable c, int i) { c.getParameter(i) = parameter }
879+
override predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
880+
c.getParameter(pos.getPosition()) = parameter
881+
}
878882

879883
override DataFlowCallable getEnclosingCallableImpl() { result = parameter.getCallable() }
880884

@@ -896,7 +900,9 @@ private module ParameterNodes {
896900
/** Gets the callable containing this implicit instance parameter. */
897901
Callable getCallable() { result = callable }
898902

899-
override predicate isParameterOf(DataFlowCallable c, int pos) { callable = c and pos = -1 }
903+
override predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
904+
callable = c and pos.isThisParameter()
905+
}
900906

901907
override DataFlowCallable getEnclosingCallableImpl() { result = callable }
902908

@@ -909,42 +915,15 @@ private module ParameterNodes {
909915
override string toStringImpl() { result = "this" }
910916
}
911917

912-
module ImplicitCapturedParameterNodeImpl {
913-
/** An implicit entry definition for a captured variable. */
914-
class SsaCapturedEntryDefinition extends Ssa::ImplicitEntryDefinition {
915-
private LocalScopeVariable v;
916-
917-
SsaCapturedEntryDefinition() { this.getSourceVariable().getAssignable() = v }
918-
919-
LocalScopeVariable getVariable() { result = v }
920-
}
921-
922-
private class CapturedVariable extends LocalScopeVariable {
923-
CapturedVariable() { this = any(SsaCapturedEntryDefinition d).getVariable() }
924-
}
925-
926-
private predicate id(CapturedVariable x, CapturedVariable y) { x = y }
927-
928-
private predicate idOf(CapturedVariable x, int y) = equivalenceRelation(id/2)(x, y)
918+
/** An implicit entry definition for a captured variable. */
919+
class SsaCapturedEntryDefinition extends Ssa::ImplicitEntryDefinition {
920+
private LocalScopeVariable v;
929921

930-
int getId(CapturedVariable v) { idOf(v, result) }
922+
SsaCapturedEntryDefinition() { this.getSourceVariable().getAssignable() = v }
931923

932-
// we model implicit parameters for captured variables starting from index `-2`,
933-
// the order is irrelevant
934-
int getParameterPosition(SsaCapturedEntryDefinition def) {
935-
exists(Callable c | c = def.getCallable() |
936-
def =
937-
rank[-result - 1](SsaCapturedEntryDefinition def0 |
938-
def0.getCallable() = c
939-
|
940-
def0 order by getId(def0.getSourceVariable().getAssignable())
941-
)
942-
)
943-
}
924+
LocalScopeVariable getVariable() { result = v }
944925
}
945926

946-
private import ImplicitCapturedParameterNodeImpl
947-
948927
/**
949928
* The value of an implicit captured variable parameter at function entry,
950929
* viewed as a node in a data flow graph.
@@ -970,8 +949,8 @@ private module ParameterNodes {
970949
/** Gets the captured variable that this implicit parameter models. */
971950
LocalScopeVariable getVariable() { result = def.getVariable() }
972951

973-
override predicate isParameterOf(DataFlowCallable c, int i) {
974-
i = getParameterPosition(def) and
952+
override predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
953+
pos.isImplicitCapturedParameterPosition(def) and
975954
c = this.getEnclosingCallable()
976955
}
977956
}
@@ -982,11 +961,13 @@ import ParameterNodes
982961
/** A data-flow node that represents a call argument. */
983962
class ArgumentNode extends Node instanceof ArgumentNodeImpl {
984963
/** Holds if this argument occurs at the given position in the given call. */
985-
final predicate argumentOf(DataFlowCall call, int pos) { super.argumentOf(call, pos) }
964+
final predicate argumentOf(DataFlowCall call, ArgumentPosition pos) {
965+
super.argumentOf(call, pos)
966+
}
986967
}
987968

988969
abstract private class ArgumentNodeImpl extends Node {
989-
abstract predicate argumentOf(DataFlowCall call, int pos);
970+
abstract predicate argumentOf(DataFlowCall call, ArgumentPosition pos);
990971
}
991972

992973
private module ArgumentNodes {
@@ -1011,7 +992,7 @@ private module ArgumentNodes {
1011992
this.asExpr() = any(CIL::Call call).getAnArgument()
1012993
}
1013994

1014-
override predicate argumentOf(DataFlowCall call, int pos) {
995+
override predicate argumentOf(DataFlowCall call, ArgumentPosition pos) {
1015996
exists(ArgumentConfiguration x, Expr c, Argument arg |
1016997
arg = this.asExpr() and
1017998
c = call.getExpr() and
@@ -1022,7 +1003,7 @@ private module ArgumentNodes {
10221003
exists(CIL::Call c, CIL::Expr arg |
10231004
arg = this.asExpr() and
10241005
c = call.getExpr() and
1025-
arg = c.getArgument(pos)
1006+
arg = c.getArgument(pos.getPosition())
10261007
)
10271008
}
10281009
}
@@ -1060,10 +1041,15 @@ private module ArgumentNodes {
10601041
)
10611042
}
10621043

1063-
override predicate argumentOf(DataFlowCall call, int pos) {
1064-
exists(ImplicitCapturedParameterNode p, boolean additionalCalls |
1044+
override predicate argumentOf(DataFlowCall call, ArgumentPosition pos) {
1045+
exists(
1046+
ImplicitCapturedParameterNode p, boolean additionalCalls, ParameterPosition ppos,
1047+
SsaCapturedEntryDefinition def
1048+
|
10651049
this.flowsInto(p, additionalCalls) and
1066-
p.isParameterOf(call.getARuntimeTarget(), pos) and
1050+
p.isParameterOf(call.getARuntimeTarget(), ppos) and
1051+
pos.isImplicitCapturedArgumentPosition(def) and
1052+
ppos.isImplicitCapturedParameterPosition(def) and
10671053
call.getControlFlowNode() = cfn and
10681054
if call instanceof TransitiveCapturedDataFlowCall
10691055
then additionalCalls = true
@@ -1091,9 +1077,9 @@ private module ArgumentNodes {
10911077

10921078
MallocNode() { this = TMallocNode(cfn) }
10931079

1094-
override predicate argumentOf(DataFlowCall call, int pos) {
1080+
override predicate argumentOf(DataFlowCall call, ArgumentPosition pos) {
10951081
call = TNonDelegateCall(cfn, _) and
1096-
pos = -1
1082+
pos.isQualifier()
10971083
}
10981084

10991085
override ControlFlow::Node getControlFlowNodeImpl() { result = cfn }
@@ -1130,9 +1116,9 @@ private module ArgumentNodes {
11301116
callCfn = any(Call c | isParamsArg(c, _, result)).getAControlFlowNode()
11311117
}
11321118

1133-
override predicate argumentOf(DataFlowCall call, int pos) {
1119+
override predicate argumentOf(DataFlowCall call, ArgumentPosition pos) {
11341120
callCfn = call.getControlFlowNode() and
1135-
pos = this.getParameter().getPosition()
1121+
pos.getPosition() = this.getParameter().getPosition()
11361122
}
11371123

11381124
override DataFlowCallable getEnclosingCallableImpl() { result = callCfn.getEnclosingCallable() }
@@ -1149,11 +1135,8 @@ private module ArgumentNodes {
11491135
private class SummaryArgumentNode extends SummaryNode, ArgumentNodeImpl {
11501136
SummaryArgumentNode() { FlowSummaryImpl::Private::summaryArgumentNode(_, this, _) }
11511137

1152-
override predicate argumentOf(DataFlowCall call, int pos) {
1153-
exists(ArgumentPosition apos |
1154-
FlowSummaryImpl::Private::summaryArgumentNode(call, this, apos) and
1155-
apos.getPosition() = pos
1156-
)
1138+
override predicate argumentOf(DataFlowCall call, ArgumentPosition pos) {
1139+
FlowSummaryImpl::Private::summaryArgumentNode(call, this, pos)
11571140
}
11581141
}
11591142
}
@@ -1870,8 +1853,8 @@ private module PostUpdateNodes {
18701853

18711854
override MallocNode getPreUpdateNode() { result.getControlFlowNode() = cfn }
18721855

1873-
override predicate argumentOf(DataFlowCall call, int pos) {
1874-
pos = -1 and
1856+
override predicate argumentOf(DataFlowCall call, ArgumentPosition pos) {
1857+
pos.isQualifier() and
18751858
any(ObjectOrCollectionInitializerConfiguration x)
18761859
.hasExprPath(_, cfn, _, call.getControlFlowNode())
18771860
}

0 commit comments

Comments
 (0)