C#: Sync files

This commit is contained in:
Tom Hvitved
2021-06-02 15:58:00 +02:00
parent d0b6808299
commit cc02c95092
2 changed files with 194 additions and 9 deletions

View File

@@ -9,6 +9,7 @@
private import FlowSummaryImplSpecific
private import DataFlowImplSpecific::Private
private import DataFlowImplSpecific::Public
private import DataFlowImplCommon as DataFlowImplCommon
/** Provides classes and predicates for defining flow summaries. */
module Public {
@@ -178,7 +179,6 @@ module Public {
*/
module Private {
private import Public
private import DataFlowImplCommon as DataFlowImplCommon
newtype TSummaryComponent =
TContentSummaryComponent(Content c) or
@@ -580,6 +580,14 @@ module Private {
* summaries into a `SummarizedCallable`s.
*/
module External {
/** Holds if `spec` is a relevant external specification. */
private predicate relevantSpec(string spec) {
summaryElement(_, spec, _, _) or
summaryElement(_, _, spec, _) or
sourceElement(_, spec, _) or
sinkElement(_, spec, _)
}
/** Holds if the `n`th component of specification `s` is `c`. */
predicate specSplit(string s, string c, int n) { relevantSpec(s) and s.splitAt(" of ", n) = c }
@@ -629,6 +637,8 @@ module Private {
or
exists(int pos | parseParam(c, pos) and result = SummaryComponent::parameter(pos))
or
c = "ReturnValue" and result = SummaryComponent::return(getReturnValueKind())
or
result = interpretComponentSpecific(c)
)
}
@@ -664,13 +674,13 @@ module Private {
}
private class SummarizedCallableExternal extends SummarizedCallable {
SummarizedCallableExternal() { externalSummary(this, _, _, _) }
SummarizedCallableExternal() { summaryElement(this, _, _, _) }
override predicate propagatesFlow(
SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue
) {
exists(string inSpec, string outSpec, string kind |
externalSummary(this, inSpec, outSpec, kind) and
summaryElement(this, inSpec, outSpec, kind) and
interpretSpec(inSpec, 0, input) and
interpretSpec(outSpec, 0, output)
|
@@ -686,6 +696,111 @@ module Private {
specSplit(spec, c, _) and
not exists(interpretComponent(c))
}
private predicate inputNeedsReference(string c) {
c = "Argument" or
parseArg(c, _)
}
private predicate outputNeedsReference(string c) {
c = "Argument" or
parseArg(c, _) or
c = "ReturnValue"
}
private predicate sourceElementRef(InterpretNode ref, string output, string kind) {
exists(SourceOrSinkElement e |
sourceElement(e, output, kind) and
if outputNeedsReference(specLast(output))
then viableCallable(ref.asCall()) = any(InterpretNode n | n.asElement() = e).asCallable()
else ref.asElement() = e
)
}
private predicate sinkElementRef(InterpretNode ref, string input, string kind) {
exists(SourceOrSinkElement e |
sinkElement(e, input, kind) and
if inputNeedsReference(specLast(input))
then viableCallable(ref.asCall()) = any(InterpretNode n | n.asElement() = e).asCallable()
else ref.asElement() = e
)
}
private predicate interpretOutput(string output, int idx, InterpretNode ref, InterpretNode node) {
sourceElementRef(ref, output, _) and
specLength(output, idx) and
node = ref
or
exists(InterpretNode mid, string c |
interpretOutput(output, idx + 1, ref, mid) and
specSplit(output, c, idx)
|
exists(int pos |
node.asNode()
.(PostUpdateNode)
.getPreUpdateNode()
.(ArgumentNode)
.argumentOf(mid.asCall(), pos)
|
c = "Argument" or parseArg(c, pos)
)
or
exists(int pos | node.asNode().(ParameterNode).isParameterOf(mid.asCallable(), pos) |
c = "Parameter" or parseParam(c, pos)
)
or
c = "ReturnValue" and
node.asNode() = getAnOutNode(mid.asCall(), getReturnValueKind())
or
interpretOutputSpecific(c, mid, node)
)
}
private predicate interpretInput(string input, int idx, InterpretNode ref, InterpretNode node) {
sinkElementRef(ref, input, _) and
specLength(input, idx) and
node = ref
or
exists(InterpretNode mid, string c |
interpretInput(input, idx + 1, ref, mid) and
specSplit(input, c, idx)
|
exists(int pos | node.asNode().(ArgumentNode).argumentOf(mid.asCall(), pos) |
c = "Argument" or parseArg(c, pos)
)
or
exists(ReturnNode ret |
c = "ReturnValue" and
ret = node.asNode() and
ret.getKind() = getReturnValueKind() and
mid.asCallable() = DataFlowImplCommon::getNodeEnclosingCallable(ret)
)
or
interpretInputSpecific(c, mid, node)
)
}
/**
* Holds if `node` is specified as a source with the given kind in a CSV flow
* model.
*/
predicate isSourceNode(InterpretNode node, string kind) {
exists(InterpretNode ref, string output |
sourceElementRef(ref, output, kind) and
interpretOutput(output, 0, ref, node)
)
}
/**
* Holds if `node` is specified as a sink with the given kind in a CSV flow
* model.
*/
predicate isSinkNode(InterpretNode node, string kind) {
exists(InterpretNode ref, string input |
sinkElementRef(ref, input, kind) and
interpretInput(input, 0, ref, node)
)
}
}
/** Provides a query predicate for outputting a set of relevant flow summaries. */

View File

@@ -78,20 +78,15 @@ DataFlowType getCallbackReturnType(DataFlowType t, ReturnKind rk) {
)
}
/** Holds if `spec` is a relevant external specification. */
predicate relevantSpec(string spec) { none() }
/**
* Holds if an external flow summary exists for `c` with input specification
* `input`, output specification `output`, and kind `kind`.
*/
predicate externalSummary(DataFlowCallable c, string input, string output, string kind) { none() }
predicate summaryElement(DataFlowCallable c, string input, string output, string kind) { none() }
/** Gets the summary component for specification component `c`, if any. */
bindingset[c]
SummaryComponent interpretComponentSpecific(string c) {
c = "ReturnValue" and result = SummaryComponent::return(any(NormalReturnKind nrk))
or
c = "Element" and result = SummaryComponent::content(any(ElementContent ec))
or
exists(Field f |
@@ -104,3 +99,78 @@ SummaryComponent interpretComponentSpecific(string c) {
result = SummaryComponent::content(any(PropertyContent pc | pc.getProperty() = p))
)
}
class SourceOrSinkElement = Element;
/**
* Holds if an external source specification exists for `e` with output specification
* `output` and kind `kind`.
*/
predicate sourceElement(Element e, string output, string kind) { none() }
/**
* Holds if an external sink specification exists for `n` with input specification
* `input` and kind `kind`.
*/
predicate sinkElement(Element e, string input, string kind) { none() }
/** Gets the return kind corresponding to specification `"ReturnValue"`. */
NormalReturnKind getReturnValueKind() { any() }
private newtype TInterpretNode =
TElement_(Element n) or
TNode_(Node n) or
TDataFlowCall_(DataFlowCall c)
/** An entity used to interpret a source/sink specification. */
class InterpretNode extends TInterpretNode {
/** Gets the element that this node corresponds to, if any. */
SourceOrSinkElement asElement() { this = TElement_(result) }
/** Gets the data-flow node that this node corresponds to, if any. */
Node asNode() { this = TNode_(result) }
/** Gets the call that this node corresponds to, if any. */
DataFlowCall asCall() { this = TDataFlowCall_(result) }
/** Gets the callable that this node corresponds to, if any. */
DataFlowCallable asCallable() { result = this.asElement() }
/** Gets a textual representation of this node. */
string toString() {
result = this.asElement().toString()
or
result = this.asNode().toString()
or
result = this.asCall().toString()
}
/** Gets the location of this node. */
Location getLocation() {
result = this.asElement().getLocation()
or
result = this.asNode().getLocation()
or
result = this.asCall().getLocation()
}
}
/** Provides additional sink specification logic required for attributes. */
predicate interpretOutputSpecific(string c, InterpretNode mid, InterpretNode node) {
exists(Node n | n = node.asNode() |
(c = "Parameter" or c = "") and
n.asParameter() = mid.asElement()
or
c = "" and
n.asExpr().(AssignableRead).getTarget().getUnboundDeclaration() = mid.asElement()
)
}
/** Provides additional sink specification logic required for attributes. */
predicate interpretInputSpecific(string c, InterpretNode mid, InterpretNode n) {
c = "" and
exists(Assignable a |
n.asNode().asExpr() = a.getAnAssignedValue() and
a.getUnboundDeclaration() = mid.asElement()
)
}