mirror of
https://github.com/github/codeql.git
synced 2025-12-24 04:36:35 +01:00
C#: Refactor SummarizedCallable.
This commit is contained in:
@@ -515,11 +515,7 @@ Element interpretElement(
|
||||
/**
|
||||
* Holds if `c` has a `generated` summary.
|
||||
*/
|
||||
predicate hasSummary(Callable c, boolean generated) {
|
||||
exists(DataFlowCallable dc |
|
||||
dc.asSummarizedCallable() = c and summaryElement(dc, _, _, _, generated)
|
||||
)
|
||||
}
|
||||
predicate hasSummary(Callable c, boolean generated) { summaryElement(c, _, _, _, generated) }
|
||||
|
||||
cached
|
||||
private module Cached {
|
||||
|
||||
@@ -114,69 +114,7 @@ module SummaryComponentStack {
|
||||
SummaryComponentStack jump(Callable c) { result = singleton(SummaryComponent::jump(c)) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A class for synthesized callables given by a summary.
|
||||
*/
|
||||
abstract class SummarizedCallable extends DotNet::Callable {
|
||||
SummarizedCallable() { this.isUnboundDeclaration() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `input` to `output` through this callable.
|
||||
*
|
||||
* `preservesValue` indicates whether this is a value-preserving step
|
||||
* or a taint-step.
|
||||
*
|
||||
* Input specifications are restricted to stacks that end with
|
||||
* `SummaryComponent::argument(_)`, preceded by zero or more
|
||||
* `SummaryComponent::return(_)` or `SummaryComponent::content(_)` components.
|
||||
*
|
||||
* Output specifications are restricted to stacks that end with
|
||||
* `SummaryComponent::return(_)` or `SummaryComponent::argument(_)`.
|
||||
*
|
||||
* Output stacks ending with `SummaryComponent::return(_)` can be preceded by zero
|
||||
* or more `SummaryComponent::content(_)` components.
|
||||
*
|
||||
* Output stacks ending with `SummaryComponent::argument(_)` can be preceded by an
|
||||
* optional `SummaryComponent::parameter(_)` component, which in turn can be preceded
|
||||
* by zero or more `SummaryComponent::content(_)` components.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate propagatesFlow(
|
||||
SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if values stored inside `content` are cleared on objects passed as
|
||||
* arguments at position `pos` to this callable.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate clearsContent(ParameterPosition pos, DataFlow::ContentSet content) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the summary is auto generated.
|
||||
*/
|
||||
predicate isAutoGenerated() { none() }
|
||||
}
|
||||
|
||||
private class SummarizedCallableAdapter extends Impl::Public::SummarizedCallable {
|
||||
private SummarizedCallable sc;
|
||||
|
||||
SummarizedCallableAdapter() { this = DataFlowDispatch::TSummarizedCallable(sc) }
|
||||
|
||||
final override predicate propagatesFlow(
|
||||
SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue
|
||||
) {
|
||||
sc.propagatesFlow(input, output, preservesValue)
|
||||
}
|
||||
|
||||
final override predicate clearsContent(ParameterPosition pos, DataFlow::ContentSet content) {
|
||||
sc.clearsContent(pos, content)
|
||||
}
|
||||
|
||||
final override predicate isAutoGenerated() { sc.isAutoGenerated() }
|
||||
}
|
||||
class SummarizedCallable = Impl::Public::SummarizedCallable;
|
||||
|
||||
private predicate recordConstructorFlow(Constructor c, int i, Property p) {
|
||||
c = any(RecordType r).getAMember() and
|
||||
|
||||
@@ -457,7 +457,7 @@ class SummaryCall extends DelegateDataFlowCall, TSummaryCall {
|
||||
|
||||
override DataFlow::Node getNode() { none() }
|
||||
|
||||
override DataFlowCallable getEnclosingCallable() { result = c }
|
||||
override DataFlowCallable getEnclosingCallable() { result.asSummarizedCallable() = c }
|
||||
|
||||
override string toString() { result = "[summary] call to " + receiver + " in " + c }
|
||||
|
||||
|
||||
@@ -976,17 +976,15 @@ private module ParameterNodes {
|
||||
SummaryParameterNode() { this = TSummaryParameterNode(sc, pos_) }
|
||||
|
||||
override predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
|
||||
sc = c and pos = pos_
|
||||
sc = c.asSummarizedCallable() and pos = pos_
|
||||
}
|
||||
|
||||
override DataFlowCallable getEnclosingCallableImpl() { result = sc }
|
||||
override DataFlowCallable getEnclosingCallableImpl() { result.asSummarizedCallable() = sc }
|
||||
|
||||
override Type getTypeImpl() {
|
||||
exists(int i |
|
||||
pos_.getPosition() = i and result = sc.asSummarizedCallable().getParameter(i).getType()
|
||||
)
|
||||
exists(int i | pos_.getPosition() = i and result = sc.getParameter(i).getType())
|
||||
or
|
||||
pos_.isThisParameter() and result = sc.asSummarizedCallable().getDeclaringType()
|
||||
pos_.isThisParameter() and result = sc.getDeclaringType()
|
||||
}
|
||||
|
||||
override ControlFlow::Node getControlFlowNodeImpl() { none() }
|
||||
@@ -1464,7 +1462,7 @@ class SummaryNode extends NodeImpl, TSummaryNode {
|
||||
|
||||
SummaryNode() { this = TSummaryNode(c, state) }
|
||||
|
||||
override DataFlowCallable getEnclosingCallableImpl() { result = c }
|
||||
override DataFlowCallable getEnclosingCallableImpl() { result.asSummarizedCallable() = c }
|
||||
|
||||
override DataFlowType getDataFlowType() {
|
||||
result = FlowSummaryImpl::Private::summaryNodeType(this)
|
||||
|
||||
@@ -195,7 +195,10 @@ module Public {
|
||||
}
|
||||
|
||||
/** A callable with a flow summary. */
|
||||
abstract class SummarizedCallable extends DataFlowCallable {
|
||||
abstract class SummarizedCallable extends SummarizedCallableBase {
|
||||
bindingset[this]
|
||||
SummarizedCallable() { any() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `input` to `output` through this callable.
|
||||
*
|
||||
@@ -493,7 +496,7 @@ module Private {
|
||||
or
|
||||
exists(ParameterPosition pos |
|
||||
parameterReadState(c, state, pos) and
|
||||
result.(ParamNode).isParameterOf(c, pos)
|
||||
result.(ParamNode).isParameterOf(inject(c), pos)
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -621,7 +624,7 @@ module Private {
|
||||
predicate summaryPostUpdateNode(Node post, Node pre) {
|
||||
exists(SummarizedCallable c, ParameterPosition pos |
|
||||
isParameterPostUpdate(post, c, pos) and
|
||||
pre.(ParamNode).isParameterOf(c, pos)
|
||||
pre.(ParamNode).isParameterOf(inject(c), pos)
|
||||
)
|
||||
or
|
||||
exists(SummarizedCallable callable, SummaryComponentStack s |
|
||||
@@ -644,7 +647,7 @@ module Private {
|
||||
* node, and back out to `p`.
|
||||
*/
|
||||
predicate summaryAllowParameterReturnInSelf(ParamNode p) {
|
||||
exists(SummarizedCallable c, ParameterPosition ppos | p.isParameterOf(c, ppos) |
|
||||
exists(SummarizedCallable c, ParameterPosition ppos | p.isParameterOf(inject(c), ppos) |
|
||||
exists(SummaryComponentStack inputContents, SummaryComponentStack outputContents |
|
||||
summary(c, inputContents, outputContents, _) and
|
||||
inputContents.bottom() = pragma[only_bind_into](TArgumentSummaryComponent(ppos)) and
|
||||
@@ -748,8 +751,11 @@ module Private {
|
||||
private predicate viableParam(
|
||||
DataFlowCall call, SummarizedCallable sc, ParameterPosition ppos, ParamNode p
|
||||
) {
|
||||
p.isParameterOf(sc, ppos) and
|
||||
sc = viableCallable(call)
|
||||
exists(DataFlowCallable c |
|
||||
c = inject(sc) and
|
||||
p.isParameterOf(c, ppos) and
|
||||
c = viableCallable(call)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -1067,7 +1073,7 @@ module Private {
|
||||
/** Provides a query predicate for outputting a set of relevant flow summaries. */
|
||||
module TestOutput {
|
||||
/** A flow summary to include in the `summary/3` query predicate. */
|
||||
abstract class RelevantSummarizedCallable extends SummarizedCallable {
|
||||
abstract class RelevantSummarizedCallable instanceof SummarizedCallable {
|
||||
/** Gets the string representation of this callable used by `summary/1`. */
|
||||
abstract string getCallableCsv();
|
||||
|
||||
@@ -1075,8 +1081,10 @@ module Private {
|
||||
predicate relevantSummary(
|
||||
SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue
|
||||
) {
|
||||
this.propagatesFlow(input, output, preservesValue)
|
||||
super.propagatesFlow(input, output, preservesValue)
|
||||
}
|
||||
|
||||
string toString() { result = super.toString() }
|
||||
}
|
||||
|
||||
/** Render the kind in the format used in flow summaries. */
|
||||
@@ -1087,7 +1095,7 @@ module Private {
|
||||
}
|
||||
|
||||
private string renderGenerated(RelevantSummarizedCallable c) {
|
||||
if c.isAutoGenerated() then result = "generated:" else result = ""
|
||||
if c.(SummarizedCallable).isAutoGenerated() then result = "generated:" else result = ""
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1117,19 +1125,21 @@ module Private {
|
||||
*/
|
||||
module RenderSummarizedCallable {
|
||||
/** A summarized callable to include in the graph. */
|
||||
abstract class RelevantSummarizedCallable extends SummarizedCallable { }
|
||||
abstract class RelevantSummarizedCallable instanceof SummarizedCallable {
|
||||
string toString() { result = super.toString() }
|
||||
}
|
||||
|
||||
private newtype TNodeOrCall =
|
||||
MkNode(Node n) {
|
||||
exists(RelevantSummarizedCallable c |
|
||||
n = summaryNode(c, _)
|
||||
or
|
||||
n.(ParamNode).isParameterOf(c, _)
|
||||
n.(ParamNode).isParameterOf(inject(c), _)
|
||||
)
|
||||
} or
|
||||
MkCall(DataFlowCall call) {
|
||||
call = summaryDataFlowCall(_) and
|
||||
call.getEnclosingCallable() instanceof RelevantSummarizedCallable
|
||||
call.getEnclosingCallable() = inject(any(RelevantSummarizedCallable c))
|
||||
}
|
||||
|
||||
private class NodeOrCall extends TNodeOrCall {
|
||||
|
||||
@@ -15,6 +15,12 @@ private import semmle.code.csharp.Unification
|
||||
private import semmle.code.csharp.dataflow.ExternalFlow
|
||||
private import semmle.code.csharp.dataflow.FlowSummary as FlowSummary
|
||||
|
||||
class SummarizedCallableBase extends Callable {
|
||||
SummarizedCallableBase() { this.isUnboundDeclaration() }
|
||||
}
|
||||
|
||||
DataFlowCallable inject(SummarizedCallable c) { result.asSummarizedCallable() = c }
|
||||
|
||||
/** Gets the parameter position of the instance parameter. */
|
||||
ArgumentPosition instanceParameterPosition() { none() } // disables implicit summary flow to `this` for callbacks
|
||||
|
||||
@@ -55,7 +61,7 @@ private DataFlowType getReturnTypeBase(DotNet::Callable c, ReturnKind rk) {
|
||||
/** Gets the return type of kind `rk` for callable `c`. */
|
||||
bindingset[c]
|
||||
DataFlowType getReturnType(SummarizedCallable c, ReturnKind rk) {
|
||||
result = getReturnTypeBase(c.asSummarizedCallable(), rk)
|
||||
result = getReturnTypeBase(c, rk)
|
||||
or
|
||||
rk =
|
||||
any(JumpReturnKind jrk | result = getReturnTypeBase(jrk.getTarget(), jrk.getTargetReturnKind()))
|
||||
@@ -85,8 +91,13 @@ DataFlowType getCallbackReturnType(DataFlowType t, ReturnKind rk) {
|
||||
)
|
||||
}
|
||||
|
||||
private predicate summaryElement0(
|
||||
DotNet::Callable c, string input, string output, string kind, boolean generated
|
||||
/**
|
||||
* Holds if an external flow summary exists for `c` with input specification
|
||||
* `input`, output specification `output`, kind `kind`, and a flag `generated`
|
||||
* stating whether the summary is autogenerated.
|
||||
*/
|
||||
predicate summaryElement(
|
||||
SummarizedCallable c, string input, string output, string kind, boolean generated
|
||||
) {
|
||||
exists(
|
||||
string namespace, string type, boolean subtypes, string name, string signature, string ext
|
||||
@@ -96,21 +107,6 @@ private predicate summaryElement0(
|
||||
)
|
||||
}
|
||||
|
||||
private class SummarizedCallableExternal extends FlowSummary::SummarizedCallable {
|
||||
SummarizedCallableExternal() { summaryElement0(this, _, _, _, _) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an external flow summary exists for `c` with input specification
|
||||
* `input`, output specification `output`, kind `kind`, and a flag `generated`
|
||||
* stating whether the summary is autogenerated.
|
||||
*/
|
||||
predicate summaryElement(
|
||||
DataFlowCallable c, string input, string output, string kind, boolean generated
|
||||
) {
|
||||
summaryElement0(c.asSummarizedCallable(), input, output, kind, generated)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an external source specification exists for `e` with output specification
|
||||
* `output`, kind `kind`, and a flag `generated` stating whether the source specification is
|
||||
|
||||
@@ -88,7 +88,10 @@ module EntityFramework {
|
||||
}
|
||||
|
||||
/** A flow summary for EntityFramework. */
|
||||
abstract class EFSummarizedCallable extends SummarizedCallable { }
|
||||
abstract class EFSummarizedCallable extends SummarizedCallable {
|
||||
bindingset[this]
|
||||
EFSummarizedCallable() { any() }
|
||||
}
|
||||
|
||||
private class DbSetAddOrUpdateRequiredSummaryComponentStack extends RequiredSummaryComponentStack {
|
||||
override predicate required(SummaryComponent head, SummaryComponentStack tail) {
|
||||
|
||||
Reference in New Issue
Block a user