Skip to content

Commit cc02c95

Browse files
committed
C#: Sync files
1 parent d0b6808 commit cc02c95

File tree

2 files changed

+194
-9
lines changed

2 files changed

+194
-9
lines changed

csharp/ql/src/semmle/code/csharp/dataflow/internal/FlowSummaryImpl.qll

Lines changed: 118 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
private import FlowSummaryImplSpecific
1010
private import DataFlowImplSpecific::Private
1111
private import DataFlowImplSpecific::Public
12+
private import DataFlowImplCommon as DataFlowImplCommon
1213

1314
/** Provides classes and predicates for defining flow summaries. */
1415
module Public {
@@ -178,7 +179,6 @@ module Public {
178179
*/
179180
module Private {
180181
private import Public
181-
private import DataFlowImplCommon as DataFlowImplCommon
182182

183183
newtype TSummaryComponent =
184184
TContentSummaryComponent(Content c) or
@@ -580,6 +580,14 @@ module Private {
580580
* summaries into a `SummarizedCallable`s.
581581
*/
582582
module External {
583+
/** Holds if `spec` is a relevant external specification. */
584+
private predicate relevantSpec(string spec) {
585+
summaryElement(_, spec, _, _) or
586+
summaryElement(_, _, spec, _) or
587+
sourceElement(_, spec, _) or
588+
sinkElement(_, spec, _)
589+
}
590+
583591
/** Holds if the `n`th component of specification `s` is `c`. */
584592
predicate specSplit(string s, string c, int n) { relevantSpec(s) and s.splitAt(" of ", n) = c }
585593

@@ -629,6 +637,8 @@ module Private {
629637
or
630638
exists(int pos | parseParam(c, pos) and result = SummaryComponent::parameter(pos))
631639
or
640+
c = "ReturnValue" and result = SummaryComponent::return(getReturnValueKind())
641+
or
632642
result = interpretComponentSpecific(c)
633643
)
634644
}
@@ -664,13 +674,13 @@ module Private {
664674
}
665675

666676
private class SummarizedCallableExternal extends SummarizedCallable {
667-
SummarizedCallableExternal() { externalSummary(this, _, _, _) }
677+
SummarizedCallableExternal() { summaryElement(this, _, _, _) }
668678

669679
override predicate propagatesFlow(
670680
SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue
671681
) {
672682
exists(string inSpec, string outSpec, string kind |
673-
externalSummary(this, inSpec, outSpec, kind) and
683+
summaryElement(this, inSpec, outSpec, kind) and
674684
interpretSpec(inSpec, 0, input) and
675685
interpretSpec(outSpec, 0, output)
676686
|
@@ -686,6 +696,111 @@ module Private {
686696
specSplit(spec, c, _) and
687697
not exists(interpretComponent(c))
688698
}
699+
700+
private predicate inputNeedsReference(string c) {
701+
c = "Argument" or
702+
parseArg(c, _)
703+
}
704+
705+
private predicate outputNeedsReference(string c) {
706+
c = "Argument" or
707+
parseArg(c, _) or
708+
c = "ReturnValue"
709+
}
710+
711+
private predicate sourceElementRef(InterpretNode ref, string output, string kind) {
712+
exists(SourceOrSinkElement e |
713+
sourceElement(e, output, kind) and
714+
if outputNeedsReference(specLast(output))
715+
then viableCallable(ref.asCall()) = any(InterpretNode n | n.asElement() = e).asCallable()
716+
else ref.asElement() = e
717+
)
718+
}
719+
720+
private predicate sinkElementRef(InterpretNode ref, string input, string kind) {
721+
exists(SourceOrSinkElement e |
722+
sinkElement(e, input, kind) and
723+
if inputNeedsReference(specLast(input))
724+
then viableCallable(ref.asCall()) = any(InterpretNode n | n.asElement() = e).asCallable()
725+
else ref.asElement() = e
726+
)
727+
}
728+
729+
private predicate interpretOutput(string output, int idx, InterpretNode ref, InterpretNode node) {
730+
sourceElementRef(ref, output, _) and
731+
specLength(output, idx) and
732+
node = ref
733+
or
734+
exists(InterpretNode mid, string c |
735+
interpretOutput(output, idx + 1, ref, mid) and
736+
specSplit(output, c, idx)
737+
|
738+
exists(int pos |
739+
node.asNode()
740+
.(PostUpdateNode)
741+
.getPreUpdateNode()
742+
.(ArgumentNode)
743+
.argumentOf(mid.asCall(), pos)
744+
|
745+
c = "Argument" or parseArg(c, pos)
746+
)
747+
or
748+
exists(int pos | node.asNode().(ParameterNode).isParameterOf(mid.asCallable(), pos) |
749+
c = "Parameter" or parseParam(c, pos)
750+
)
751+
or
752+
c = "ReturnValue" and
753+
node.asNode() = getAnOutNode(mid.asCall(), getReturnValueKind())
754+
or
755+
interpretOutputSpecific(c, mid, node)
756+
)
757+
}
758+
759+
private predicate interpretInput(string input, int idx, InterpretNode ref, InterpretNode node) {
760+
sinkElementRef(ref, input, _) and
761+
specLength(input, idx) and
762+
node = ref
763+
or
764+
exists(InterpretNode mid, string c |
765+
interpretInput(input, idx + 1, ref, mid) and
766+
specSplit(input, c, idx)
767+
|
768+
exists(int pos | node.asNode().(ArgumentNode).argumentOf(mid.asCall(), pos) |
769+
c = "Argument" or parseArg(c, pos)
770+
)
771+
or
772+
exists(ReturnNode ret |
773+
c = "ReturnValue" and
774+
ret = node.asNode() and
775+
ret.getKind() = getReturnValueKind() and
776+
mid.asCallable() = DataFlowImplCommon::getNodeEnclosingCallable(ret)
777+
)
778+
or
779+
interpretInputSpecific(c, mid, node)
780+
)
781+
}
782+
783+
/**
784+
* Holds if `node` is specified as a source with the given kind in a CSV flow
785+
* model.
786+
*/
787+
predicate isSourceNode(InterpretNode node, string kind) {
788+
exists(InterpretNode ref, string output |
789+
sourceElementRef(ref, output, kind) and
790+
interpretOutput(output, 0, ref, node)
791+
)
792+
}
793+
794+
/**
795+
* Holds if `node` is specified as a sink with the given kind in a CSV flow
796+
* model.
797+
*/
798+
predicate isSinkNode(InterpretNode node, string kind) {
799+
exists(InterpretNode ref, string input |
800+
sinkElementRef(ref, input, kind) and
801+
interpretInput(input, 0, ref, node)
802+
)
803+
}
689804
}
690805

691806
/** Provides a query predicate for outputting a set of relevant flow summaries. */

csharp/ql/src/semmle/code/csharp/dataflow/internal/FlowSummaryImplSpecific.qll

Lines changed: 76 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -78,20 +78,15 @@ DataFlowType getCallbackReturnType(DataFlowType t, ReturnKind rk) {
7878
)
7979
}
8080

81-
/** Holds if `spec` is a relevant external specification. */
82-
predicate relevantSpec(string spec) { none() }
83-
8481
/**
8582
* Holds if an external flow summary exists for `c` with input specification
8683
* `input`, output specification `output`, and kind `kind`.
8784
*/
88-
predicate externalSummary(DataFlowCallable c, string input, string output, string kind) { none() }
85+
predicate summaryElement(DataFlowCallable c, string input, string output, string kind) { none() }
8986

9087
/** Gets the summary component for specification component `c`, if any. */
9188
bindingset[c]
9289
SummaryComponent interpretComponentSpecific(string c) {
93-
c = "ReturnValue" and result = SummaryComponent::return(any(NormalReturnKind nrk))
94-
or
9590
c = "Element" and result = SummaryComponent::content(any(ElementContent ec))
9691
or
9792
exists(Field f |
@@ -104,3 +99,78 @@ SummaryComponent interpretComponentSpecific(string c) {
10499
result = SummaryComponent::content(any(PropertyContent pc | pc.getProperty() = p))
105100
)
106101
}
102+
103+
class SourceOrSinkElement = Element;
104+
105+
/**
106+
* Holds if an external source specification exists for `e` with output specification
107+
* `output` and kind `kind`.
108+
*/
109+
predicate sourceElement(Element e, string output, string kind) { none() }
110+
111+
/**
112+
* Holds if an external sink specification exists for `n` with input specification
113+
* `input` and kind `kind`.
114+
*/
115+
predicate sinkElement(Element e, string input, string kind) { none() }
116+
117+
/** Gets the return kind corresponding to specification `"ReturnValue"`. */
118+
NormalReturnKind getReturnValueKind() { any() }
119+
120+
private newtype TInterpretNode =
121+
TElement_(Element n) or
122+
TNode_(Node n) or
123+
TDataFlowCall_(DataFlowCall c)
124+
125+
/** An entity used to interpret a source/sink specification. */
126+
class InterpretNode extends TInterpretNode {
127+
/** Gets the element that this node corresponds to, if any. */
128+
SourceOrSinkElement asElement() { this = TElement_(result) }
129+
130+
/** Gets the data-flow node that this node corresponds to, if any. */
131+
Node asNode() { this = TNode_(result) }
132+
133+
/** Gets the call that this node corresponds to, if any. */
134+
DataFlowCall asCall() { this = TDataFlowCall_(result) }
135+
136+
/** Gets the callable that this node corresponds to, if any. */
137+
DataFlowCallable asCallable() { result = this.asElement() }
138+
139+
/** Gets a textual representation of this node. */
140+
string toString() {
141+
result = this.asElement().toString()
142+
or
143+
result = this.asNode().toString()
144+
or
145+
result = this.asCall().toString()
146+
}
147+
148+
/** Gets the location of this node. */
149+
Location getLocation() {
150+
result = this.asElement().getLocation()
151+
or
152+
result = this.asNode().getLocation()
153+
or
154+
result = this.asCall().getLocation()
155+
}
156+
}
157+
158+
/** Provides additional sink specification logic required for attributes. */
159+
predicate interpretOutputSpecific(string c, InterpretNode mid, InterpretNode node) {
160+
exists(Node n | n = node.asNode() |
161+
(c = "Parameter" or c = "") and
162+
n.asParameter() = mid.asElement()
163+
or
164+
c = "" and
165+
n.asExpr().(AssignableRead).getTarget().getUnboundDeclaration() = mid.asElement()
166+
)
167+
}
168+
169+
/** Provides additional sink specification logic required for attributes. */
170+
predicate interpretInputSpecific(string c, InterpretNode mid, InterpretNode n) {
171+
c = "" and
172+
exists(Assignable a |
173+
n.asNode().asExpr() = a.getAnAssignedValue() and
174+
a.getUnboundDeclaration() = mid.asElement()
175+
)
176+
}

0 commit comments

Comments
 (0)