mirror of
https://github.com/github/codeql.git
synced 2025-12-17 01:03:14 +01:00
Data flow: Synthesize parameter return nodes
This commit is contained in:
@@ -546,7 +546,7 @@ module ProductFlow {
|
||||
Flow1::PathGraph::edges(pred1, succ1, _, _) and
|
||||
exists(ReturnKindExt returnKind |
|
||||
succ1.getNode() = returnKind.getAnOutNode(call) and
|
||||
pred1.getNode().(ReturnNodeExt).getKind() = returnKind
|
||||
paramReturnNode(_, pred1.asParameterReturnNode(), _, returnKind)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -574,7 +574,7 @@ module ProductFlow {
|
||||
Flow2::PathGraph::edges(pred2, succ2, _, _) and
|
||||
exists(ReturnKindExt returnKind |
|
||||
succ2.getNode() = returnKind.getAnOutNode(call) and
|
||||
pred2.getNode().(ReturnNodeExt).getKind() = returnKind
|
||||
paramReturnNode(_, pred2.asParameterReturnNode(), _, returnKind)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,29 @@
|
||||
private import CaptureModelsSpecific
|
||||
private import CaptureModelsPrinting
|
||||
|
||||
/**
|
||||
* A node from which flow can return to the caller. This is either a regular
|
||||
* `ReturnNode` or a `PostUpdateNode` corresponding to the value of a parameter.
|
||||
*/
|
||||
private class ReturnNodeExt extends DataFlow::Node {
|
||||
private DataFlowImplCommon::ReturnKindExt kind;
|
||||
|
||||
ReturnNodeExt() {
|
||||
kind = DataFlowImplCommon::getValueReturnPosition(this).getKind() or
|
||||
kind = DataFlowImplCommon::getParamReturnPosition(this, _).getKind()
|
||||
}
|
||||
|
||||
string getOutput() {
|
||||
kind instanceof DataFlowImplCommon::ValueReturnKind and
|
||||
result = "ReturnValue"
|
||||
or
|
||||
exists(ParameterPosition pos |
|
||||
pos = kind.(DataFlowImplCommon::ParamUpdateReturnKind).getPosition() and
|
||||
result = paramReturnNodeAsOutput(returnNodeEnclosingCallable(this), pos)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class DataFlowTargetApi extends TargetApiSpecific {
|
||||
DataFlowTargetApi() { not isUninterestingForDataFlowModels(this) }
|
||||
}
|
||||
@@ -65,7 +88,7 @@ string asInputArgument(DataFlow::Node source) { result = asInputArgumentSpecific
|
||||
* Gets the summary model of `api`, if it follows the `fluent` programming pattern (returns `this`).
|
||||
*/
|
||||
string captureQualifierFlow(TargetApiSpecific api) {
|
||||
exists(DataFlowImplCommon::ReturnNodeExt ret |
|
||||
exists(ReturnNodeExt ret |
|
||||
api = returnNodeEnclosingCallable(ret) and
|
||||
isOwnInstanceAccessNode(ret)
|
||||
) and
|
||||
@@ -130,7 +153,7 @@ module ThroughFlowConfig implements DataFlow::StateConfigSig {
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink, FlowState state) {
|
||||
sink instanceof DataFlowImplCommon::ReturnNodeExt and
|
||||
sink instanceof ReturnNodeExt and
|
||||
not isOwnInstanceAccessNode(sink) and
|
||||
not exists(captureQualifierFlow(sink.asExpr().getEnclosingCallable())) and
|
||||
(state instanceof TaintRead or state instanceof TaintStore)
|
||||
@@ -171,14 +194,11 @@ private module ThroughFlow = TaintTracking::GlobalWithState<ThroughFlowConfig>;
|
||||
* Gets the summary model(s) of `api`, if there is flow from parameters to return value or parameter.
|
||||
*/
|
||||
string captureThroughFlow(DataFlowTargetApi api) {
|
||||
exists(
|
||||
DataFlow::ParameterNode p, DataFlowImplCommon::ReturnNodeExt returnNodeExt, string input,
|
||||
string output
|
||||
|
|
||||
exists(DataFlow::ParameterNode p, ReturnNodeExt returnNodeExt, string input, string output |
|
||||
ThroughFlow::flow(p, returnNodeExt) and
|
||||
returnNodeExt.(DataFlow::Node).getEnclosingCallable() = api and
|
||||
input = parameterNodeAsInput(p) and
|
||||
output = returnNodeAsOutput(returnNodeExt) and
|
||||
output = returnNodeExt.getOutput() and
|
||||
input != output and
|
||||
result = ModelPrinting::asTaintModel(api, input, output)
|
||||
)
|
||||
@@ -196,7 +216,7 @@ module FromSourceConfig implements DataFlow::ConfigSig {
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(DataFlowTargetApi c |
|
||||
sink instanceof DataFlowImplCommon::ReturnNodeExt and
|
||||
sink instanceof ReturnNodeExt and
|
||||
sink.getEnclosingCallable() = c
|
||||
)
|
||||
}
|
||||
@@ -214,12 +234,12 @@ private module FromSource = TaintTracking::Global<FromSourceConfig>;
|
||||
* Gets the source model(s) of `api`, if there is flow from an existing known source to the return of `api`.
|
||||
*/
|
||||
string captureSource(DataFlowTargetApi api) {
|
||||
exists(DataFlow::Node source, DataFlow::Node sink, string kind |
|
||||
exists(DataFlow::Node source, ReturnNodeExt sink, string kind |
|
||||
FromSource::flow(source, sink) and
|
||||
ExternalFlow::sourceNode(source, kind) and
|
||||
api = sink.getEnclosingCallable() and
|
||||
isRelevantSourceKind(kind) and
|
||||
result = ModelPrinting::asSourceModel(api, returnNodeAsOutput(sink), kind)
|
||||
result = ModelPrinting::asSourceModel(api, sink.getOutput(), kind)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ private import semmle.code.csharp.frameworks.system.linq.Expressions
|
||||
import semmle.code.csharp.dataflow.internal.ExternalFlow as ExternalFlow
|
||||
import semmle.code.csharp.dataflow.internal.DataFlowImplCommon as DataFlowImplCommon
|
||||
import semmle.code.csharp.dataflow.internal.DataFlowPrivate as DataFlowPrivate
|
||||
import semmle.code.csharp.dataflow.internal.DataFlowDispatch as DataFlowDispatch
|
||||
|
||||
module DataFlow = CS::DataFlow;
|
||||
|
||||
@@ -133,32 +134,24 @@ string parameterAccess(CS::Parameter p) {
|
||||
|
||||
class InstanceParameterNode = DataFlowPrivate::InstanceParameterNode;
|
||||
|
||||
pragma[nomagic]
|
||||
private CS::Parameter getParameter(DataFlowImplCommon::ReturnNodeExt node, ParameterPosition pos) {
|
||||
result = node.(DataFlow::Node).getEnclosingCallable().getParameter(pos.getPosition())
|
||||
}
|
||||
class ParameterPosition = DataFlowDispatch::ParameterPosition;
|
||||
|
||||
/**
|
||||
* Gets the MaD string representation of the the return node `node`.
|
||||
* Gets the MaD string represention of return through parameter at position
|
||||
* `pos` of callable `c`.
|
||||
*/
|
||||
string returnNodeAsOutput(DataFlowImplCommon::ReturnNodeExt node) {
|
||||
if node.getKind() instanceof DataFlowImplCommon::ValueReturnKind
|
||||
then result = "ReturnValue"
|
||||
else
|
||||
exists(ParameterPosition pos |
|
||||
pos = node.getKind().(DataFlowImplCommon::ParamUpdateReturnKind).getPosition()
|
||||
|
|
||||
result = parameterAccess(getParameter(node, pos))
|
||||
or
|
||||
pos.isThisParameter() and
|
||||
result = qualifierString()
|
||||
)
|
||||
bindingset[c]
|
||||
string paramReturnNodeAsOutput(CS::Callable c, ParameterPosition pos) {
|
||||
result = parameterAccess(c.getParameter(pos.getPosition()))
|
||||
or
|
||||
pos.isThisParameter() and
|
||||
result = qualifierString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the enclosing callable of `ret`.
|
||||
*/
|
||||
CS::Callable returnNodeEnclosingCallable(DataFlowImplCommon::ReturnNodeExt ret) {
|
||||
CS::Callable returnNodeEnclosingCallable(DataFlow::Node ret) {
|
||||
result = DataFlowImplCommon::getNodeEnclosingCallable(ret).asCallable()
|
||||
}
|
||||
|
||||
|
||||
@@ -236,10 +236,10 @@ module SourceSinkInterpretationInput implements
|
||||
/** Provides additional source specification logic. */
|
||||
bindingset[c]
|
||||
predicate interpretInput(string c, InterpretNode mid, InterpretNode node) {
|
||||
exists(int pos, ReturnNodeExt ret |
|
||||
exists(int pos, ReturnNode ret |
|
||||
parseReturn(c, pos) and
|
||||
ret = node.asNode() and
|
||||
ret.getKind().(ValueReturnKind).getKind() = getReturnKind(pos) and
|
||||
ret.getKind() = getReturnKind(pos) and
|
||||
mid.asCallable() = getNodeEnclosingCallable(ret)
|
||||
)
|
||||
or
|
||||
|
||||
@@ -6,6 +6,29 @@
|
||||
private import CaptureModelsSpecific
|
||||
private import CaptureModelsPrinting
|
||||
|
||||
/**
|
||||
* A node from which flow can return to the caller. This is either a regular
|
||||
* `ReturnNode` or a `PostUpdateNode` corresponding to the value of a parameter.
|
||||
*/
|
||||
private class ReturnNodeExt extends DataFlow::Node {
|
||||
private DataFlowImplCommon::ReturnKindExt kind;
|
||||
|
||||
ReturnNodeExt() {
|
||||
kind = DataFlowImplCommon::getValueReturnPosition(this).getKind() or
|
||||
kind = DataFlowImplCommon::getParamReturnPosition(this, _).getKind()
|
||||
}
|
||||
|
||||
string getOutput() {
|
||||
kind instanceof DataFlowImplCommon::ValueReturnKind and
|
||||
result = "ReturnValue"
|
||||
or
|
||||
exists(ParameterPosition pos |
|
||||
pos = kind.(DataFlowImplCommon::ParamUpdateReturnKind).getPosition() and
|
||||
result = paramReturnNodeAsOutput(returnNodeEnclosingCallable(this), pos)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class DataFlowTargetApi extends TargetApiSpecific {
|
||||
DataFlowTargetApi() { not isUninterestingForDataFlowModels(this) }
|
||||
}
|
||||
@@ -65,7 +88,7 @@ string asInputArgument(DataFlow::Node source) { result = asInputArgumentSpecific
|
||||
* Gets the summary model of `api`, if it follows the `fluent` programming pattern (returns `this`).
|
||||
*/
|
||||
string captureQualifierFlow(TargetApiSpecific api) {
|
||||
exists(DataFlowImplCommon::ReturnNodeExt ret |
|
||||
exists(ReturnNodeExt ret |
|
||||
api = returnNodeEnclosingCallable(ret) and
|
||||
isOwnInstanceAccessNode(ret)
|
||||
) and
|
||||
@@ -130,7 +153,7 @@ module ThroughFlowConfig implements DataFlow::StateConfigSig {
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink, FlowState state) {
|
||||
sink instanceof DataFlowImplCommon::ReturnNodeExt and
|
||||
sink instanceof ReturnNodeExt and
|
||||
not isOwnInstanceAccessNode(sink) and
|
||||
not exists(captureQualifierFlow(sink.asExpr().getEnclosingCallable())) and
|
||||
(state instanceof TaintRead or state instanceof TaintStore)
|
||||
@@ -171,14 +194,11 @@ private module ThroughFlow = TaintTracking::GlobalWithState<ThroughFlowConfig>;
|
||||
* Gets the summary model(s) of `api`, if there is flow from parameters to return value or parameter.
|
||||
*/
|
||||
string captureThroughFlow(DataFlowTargetApi api) {
|
||||
exists(
|
||||
DataFlow::ParameterNode p, DataFlowImplCommon::ReturnNodeExt returnNodeExt, string input,
|
||||
string output
|
||||
|
|
||||
exists(DataFlow::ParameterNode p, ReturnNodeExt returnNodeExt, string input, string output |
|
||||
ThroughFlow::flow(p, returnNodeExt) and
|
||||
returnNodeExt.(DataFlow::Node).getEnclosingCallable() = api and
|
||||
input = parameterNodeAsInput(p) and
|
||||
output = returnNodeAsOutput(returnNodeExt) and
|
||||
output = returnNodeExt.getOutput() and
|
||||
input != output and
|
||||
result = ModelPrinting::asTaintModel(api, input, output)
|
||||
)
|
||||
@@ -196,7 +216,7 @@ module FromSourceConfig implements DataFlow::ConfigSig {
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(DataFlowTargetApi c |
|
||||
sink instanceof DataFlowImplCommon::ReturnNodeExt and
|
||||
sink instanceof ReturnNodeExt and
|
||||
sink.getEnclosingCallable() = c
|
||||
)
|
||||
}
|
||||
@@ -214,12 +234,12 @@ private module FromSource = TaintTracking::Global<FromSourceConfig>;
|
||||
* Gets the source model(s) of `api`, if there is flow from an existing known source to the return of `api`.
|
||||
*/
|
||||
string captureSource(DataFlowTargetApi api) {
|
||||
exists(DataFlow::Node source, DataFlow::Node sink, string kind |
|
||||
exists(DataFlow::Node source, ReturnNodeExt sink, string kind |
|
||||
FromSource::flow(source, sink) and
|
||||
ExternalFlow::sourceNode(source, kind) and
|
||||
api = sink.getEnclosingCallable() and
|
||||
isRelevantSourceKind(kind) and
|
||||
result = ModelPrinting::asSourceModel(api, returnNodeAsOutput(sink), kind)
|
||||
result = ModelPrinting::asSourceModel(api, sink.getOutput(), kind)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ private import semmle.code.java.dataflow.TaintTracking as Tt
|
||||
import semmle.code.java.dataflow.ExternalFlow as ExternalFlow
|
||||
import semmle.code.java.dataflow.internal.DataFlowImplCommon as DataFlowImplCommon
|
||||
import semmle.code.java.dataflow.internal.DataFlowPrivate as DataFlowPrivate
|
||||
import semmle.code.java.dataflow.internal.DataFlowDispatch as DataFlowDispatch
|
||||
|
||||
module DataFlow = Df::DataFlow;
|
||||
|
||||
@@ -202,26 +203,23 @@ string parameterAccess(J::Parameter p) {
|
||||
|
||||
class InstanceParameterNode = DataFlow::InstanceParameterNode;
|
||||
|
||||
class ParameterPosition = DataFlowDispatch::ParameterPosition;
|
||||
|
||||
/**
|
||||
* Gets the MaD string represention of the the return node `node`.
|
||||
* Gets the MaD string represention of return through parameter at position
|
||||
* `pos` of callable `c`.
|
||||
*/
|
||||
string returnNodeAsOutput(DataFlowImplCommon::ReturnNodeExt node) {
|
||||
if node.getKind() instanceof DataFlowImplCommon::ValueReturnKind
|
||||
then result = "ReturnValue"
|
||||
else
|
||||
exists(int pos |
|
||||
pos = node.getKind().(DataFlowImplCommon::ParamUpdateReturnKind).getPosition()
|
||||
|
|
||||
result = parameterAccess(node.(DataFlow::Node).getEnclosingCallable().getParameter(pos))
|
||||
or
|
||||
result = qualifierString() and pos = -1
|
||||
)
|
||||
bindingset[c]
|
||||
string paramReturnNodeAsOutput(Callable c, ParameterPosition pos) {
|
||||
result = parameterAccess(c.getParameter(pos))
|
||||
or
|
||||
result = qualifierString() and pos = -1
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the enclosing callable of `ret`.
|
||||
*/
|
||||
Callable returnNodeEnclosingCallable(DataFlowImplCommon::ReturnNodeExt ret) {
|
||||
Callable returnNodeEnclosingCallable(DataFlow::Node ret) {
|
||||
result = DataFlowImplCommon::getNodeEnclosingCallable(ret).asCallable()
|
||||
}
|
||||
|
||||
|
||||
@@ -163,6 +163,9 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
TNodeNormal(Node n) or
|
||||
TNodeImplicitRead(Node n, boolean hasRead) {
|
||||
Config::allowImplicitRead(n, _) and hasRead = [false, true]
|
||||
} or
|
||||
TParamReturnNode(ParameterNode p, SndLevelScopeOption scope) {
|
||||
paramReturnNode(_, p, scope, _)
|
||||
}
|
||||
|
||||
private class NodeEx extends TNodeEx {
|
||||
@@ -170,13 +173,21 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
result = this.asNode().toString()
|
||||
or
|
||||
exists(Node n | this.isImplicitReadNode(n, _) | result = n.toString() + " [Ext]")
|
||||
or
|
||||
result = this.asParamReturnNode().toString() + " [Return]"
|
||||
}
|
||||
|
||||
Node asNode() { this = TNodeNormal(result) }
|
||||
|
||||
predicate isImplicitReadNode(Node n, boolean hasRead) { this = TNodeImplicitRead(n, hasRead) }
|
||||
|
||||
Node projectToNode() { this = TNodeNormal(result) or this = TNodeImplicitRead(result, _) }
|
||||
ParameterNode asParamReturnNode() { this = TParamReturnNode(result, _) }
|
||||
|
||||
Node projectToNode() {
|
||||
this = TNodeNormal(result) or
|
||||
this = TNodeImplicitRead(result, _) or
|
||||
this = TParamReturnNode(result, _)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private DataFlowCallable getEnclosingCallable0() {
|
||||
@@ -189,7 +200,11 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private DataFlowType getDataFlowType0() { nodeDataFlowType(this.asNode(), result) }
|
||||
private DataFlowType getDataFlowType0() {
|
||||
nodeDataFlowType(this.asNode(), result)
|
||||
or
|
||||
nodeDataFlowType(this.asParamReturnNode(), result)
|
||||
}
|
||||
|
||||
pragma[inline]
|
||||
DataFlowType getDataFlowType() {
|
||||
@@ -215,12 +230,21 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
ParameterPosition getPosition() { this.isParameterOf(_, result) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A node from which flow can return to the caller. This is either a regular
|
||||
* `ReturnNode` or a synthesized node for flow out via a parameter.
|
||||
*/
|
||||
private class RetNodeEx extends NodeEx {
|
||||
RetNodeEx() { this.asNode() instanceof ReturnNodeExt }
|
||||
private ReturnPosition pos;
|
||||
|
||||
ReturnPosition getReturnPosition() { result = getReturnPosition(this.asNode()) }
|
||||
RetNodeEx() {
|
||||
pos = getValueReturnPosition(this.asNode()) or
|
||||
pos = getParamReturnPosition(_, this.asParamReturnNode())
|
||||
}
|
||||
|
||||
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
|
||||
ReturnPosition getReturnPosition() { result = pos }
|
||||
|
||||
ReturnKindExt getKind() { result = pos.getKind() }
|
||||
}
|
||||
|
||||
private predicate inBarrier(NodeEx node) {
|
||||
@@ -347,6 +371,14 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
not fullBarrier(node1) and
|
||||
model = ""
|
||||
)
|
||||
or
|
||||
exists(Node n1, Node n2, SndLevelScopeOption scope |
|
||||
node1.asNode() = n1 and
|
||||
node2 = TParamReturnNode(n2, scope) and
|
||||
paramReturnNode(pragma[only_bind_into](n1), pragma[only_bind_into](n2),
|
||||
pragma[only_bind_into](scope), _) and
|
||||
model = ""
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1113,26 +1145,17 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
result = getAdditionalFlowIntoCallNodeTerm(arg.projectToNode(), p.projectToNode())
|
||||
}
|
||||
|
||||
private module SndLevelScopeOption = Option<DataFlowSecondLevelScope>;
|
||||
|
||||
private class SndLevelScopeOption = SndLevelScopeOption::Option;
|
||||
|
||||
pragma[nomagic]
|
||||
private SndLevelScopeOption getScope(RetNodeEx ret) {
|
||||
result = SndLevelScopeOption::some(getSecondLevelScopeCached(ret.asNode()))
|
||||
or
|
||||
result instanceof SndLevelScopeOption::None and
|
||||
not exists(getSecondLevelScopeCached(ret.asNode()))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate returnCallEdge1(
|
||||
DataFlowCallable c, SndLevelScopeOption scope, DataFlowCall call, NodeEx out
|
||||
) {
|
||||
exists(RetNodeEx ret |
|
||||
flowOutOfCallNodeCand1(call, ret, _, out) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
scope = getScope(ret)
|
||||
c = ret.getEnclosingCallable()
|
||||
|
|
||||
scope = getSecondLevelScopeCached(ret.asNode())
|
||||
or
|
||||
ret = TParamReturnNode(_, scope)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3802,6 +3825,8 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
not this instanceof PathNodeSink
|
||||
or
|
||||
this.getNodeEx() instanceof TNodeImplicitRead
|
||||
or
|
||||
hiddenNode(this.getNodeEx().asParamReturnNode())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3925,6 +3950,9 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
/** Gets the underlying `Node`. */
|
||||
final Node getNode() { super.getNodeEx().projectToNode() = result }
|
||||
|
||||
/** Gets the parameter node through which data is returned, if any. */
|
||||
final ParameterNode asParameterReturnNode() { result = super.getNodeEx().asParamReturnNode() }
|
||||
|
||||
/** Gets the `FlowState` of this node. */
|
||||
final FlowState getState() { result = super.getState() }
|
||||
|
||||
@@ -5620,7 +5648,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
or
|
||||
exists(ReturnPosition pos |
|
||||
revPartialPathIntoReturn(mid, pos, state, sc1, sc2, sc3, _, ap) and
|
||||
pos = getReturnPosition(node.asNode()) and
|
||||
pos = node.(RetNodeEx).getReturnPosition() and
|
||||
isStoreStep = false
|
||||
)
|
||||
or
|
||||
|
||||
@@ -2,6 +2,7 @@ private import codeql.dataflow.DataFlow
|
||||
private import codeql.typetracking.TypeTracking as Tt
|
||||
private import codeql.util.Location
|
||||
private import codeql.util.Unit
|
||||
private import codeql.util.Option
|
||||
|
||||
module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
|
||||
private import Lang
|
||||
@@ -137,7 +138,7 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
|
||||
predicate callStep(Node n1, LocalSourceNode n2) { viableParamArg(_, n2, n1) }
|
||||
|
||||
predicate returnStep(Node n1, LocalSourceNode n2) {
|
||||
viableReturnPosOut(_, getReturnPosition(n1), n2)
|
||||
viableReturnPosOut(_, [getValueReturnPosition(n1), getParamReturnPosition(n1, _)], n2)
|
||||
}
|
||||
|
||||
predicate hasFeatureBacktrackStoreTarget() { none() }
|
||||
@@ -222,9 +223,18 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private TReturnPositionSimple getReturnPositionSimple(ReturnNode ret, ReturnKind kind) {
|
||||
result = TReturnPositionSimple0(getNodeEnclosingCallable(ret), kind)
|
||||
pragma[nomagic]
|
||||
private predicate hasSimpleReturnKindIn(ReturnNode ret, ReturnKind kind, DataFlowCallable c) {
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
kind = ret.getKind()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private TReturnPositionSimple getReturnPositionSimple(ReturnNode ret) {
|
||||
exists(ReturnKind kind, DataFlowCallable c |
|
||||
hasSimpleReturnKindIn(ret, kind, c) and
|
||||
result = TReturnPositionSimple0(c, kind)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -349,7 +359,7 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
|
||||
// flow out of a callable
|
||||
exists(TReturnPositionSimple pos |
|
||||
revLambdaFlowOut(lambdaCall, kind, pos, t, toJump, lastCall) and
|
||||
getReturnPositionSimple(node, node.(ReturnNode).getKind()) = pos and
|
||||
pos = getReturnPositionSimple(node) and
|
||||
toReturn = true
|
||||
)
|
||||
}
|
||||
@@ -606,6 +616,10 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
|
||||
import PrunedViableImpl<DefaultPrunedViableImplInput>
|
||||
}
|
||||
|
||||
module SndLevelScopeOption = Option<DataFlowSecondLevelScope>;
|
||||
|
||||
class SndLevelScopeOption = SndLevelScopeOption::Option;
|
||||
|
||||
cached
|
||||
private module Cached {
|
||||
/**
|
||||
@@ -617,7 +631,12 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
|
||||
predicate forceCachingInSameStage() { any() }
|
||||
|
||||
cached
|
||||
DataFlowSecondLevelScope getSecondLevelScopeCached(Node n) { result = getSecondLevelScope(n) }
|
||||
SndLevelScopeOption getSecondLevelScopeCached(Node n) {
|
||||
result = SndLevelScopeOption::some(getSecondLevelScope(n))
|
||||
or
|
||||
result instanceof SndLevelScopeOption::None and
|
||||
not exists(getSecondLevelScope(n))
|
||||
}
|
||||
|
||||
cached
|
||||
predicate nodeEnclosingCallable(Node n, DataFlowCallable c) { c = nodeGetEnclosingCallable(n) }
|
||||
@@ -663,13 +682,17 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
|
||||
}
|
||||
|
||||
cached
|
||||
predicate returnNodeExt(Node n, ReturnKindExt k) {
|
||||
k = TValueReturn(n.(ReturnNode).getKind())
|
||||
or
|
||||
exists(ParamNode p, ParameterPosition pos |
|
||||
predicate valueReturnNode(ReturnNode n, ReturnKindExt k) { k = TValueReturn(n.getKind()) }
|
||||
|
||||
cached
|
||||
predicate paramReturnNode(
|
||||
PostUpdateNode n, ParamNode p, SndLevelScopeOption scope, ReturnKindExt k
|
||||
) {
|
||||
exists(ParameterPosition pos |
|
||||
parameterValueFlowsToPreUpdate(p, n) and
|
||||
p.isParameterOf(_, pos) and
|
||||
k = TParamUpdate(pos)
|
||||
k = TParamUpdate(pos) and
|
||||
scope = getSecondLevelScopeCached(n)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1221,10 +1244,9 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
|
||||
cached
|
||||
newtype TReturnPosition =
|
||||
TReturnPosition0(DataFlowCallable c, ReturnKindExt kind) {
|
||||
exists(ReturnNodeExt ret |
|
||||
c = returnNodeGetEnclosingCallable(ret) and
|
||||
kind = ret.getKind()
|
||||
)
|
||||
hasValueReturnKindIn(_, kind, c)
|
||||
or
|
||||
hasParamReturnKindIn(_, _, kind, c)
|
||||
}
|
||||
|
||||
cached
|
||||
@@ -1842,17 +1864,6 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A node from which flow can return to the caller. This is either a regular
|
||||
* `ReturnNode` or a `PostUpdateNode` corresponding to the value of a parameter.
|
||||
*/
|
||||
class ReturnNodeExt extends NodeFinal {
|
||||
ReturnNodeExt() { returnNodeExt(this, _) }
|
||||
|
||||
/** Gets the kind of this returned value. */
|
||||
ReturnKindExt getKind() { returnNodeExt(this, result) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A node to which data can flow from a call. Either an ordinary out node
|
||||
* or a post-update node associated with a call argument.
|
||||
@@ -1930,20 +1941,34 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
|
||||
nodeDataFlowType(pragma[only_bind_out](n), pragma[only_bind_into](result))
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private DataFlowCallable returnNodeGetEnclosingCallable(ReturnNodeExt ret) {
|
||||
result = getNodeEnclosingCallable(ret)
|
||||
pragma[nomagic]
|
||||
private predicate hasValueReturnKindIn(ReturnNode ret, ReturnKindExt kind, DataFlowCallable c) {
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
valueReturnNode(ret, kind)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private ReturnPosition getReturnPosition0(ReturnNodeExt ret, ReturnKindExt kind) {
|
||||
result.getCallable() = returnNodeGetEnclosingCallable(ret) and
|
||||
kind = result.getKind()
|
||||
pragma[nomagic]
|
||||
private predicate hasParamReturnKindIn(
|
||||
PostUpdateNode n, ParamNode p, ReturnKindExt kind, DataFlowCallable c
|
||||
) {
|
||||
c = getNodeEnclosingCallable(n) and
|
||||
paramReturnNode(n, p, _, kind)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
ReturnPosition getReturnPosition(ReturnNodeExt ret) {
|
||||
result = getReturnPosition0(ret, ret.getKind())
|
||||
pragma[nomagic]
|
||||
ReturnPosition getValueReturnPosition(ReturnNode ret) {
|
||||
exists(ReturnKindExt kind, DataFlowCallable c |
|
||||
hasValueReturnKindIn(ret, kind, c) and
|
||||
result = TReturnPosition0(c, kind)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
ReturnPosition getParamReturnPosition(PostUpdateNode n, ParamNode p) {
|
||||
exists(ReturnKindExt kind, DataFlowCallable c |
|
||||
hasParamReturnKindIn(n, p, kind, c) and
|
||||
result = TReturnPosition0(c, kind)
|
||||
)
|
||||
}
|
||||
|
||||
/** An optional Boolean value. */
|
||||
|
||||
@@ -1692,10 +1692,11 @@ module Make<
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(ReturnNodeExt ret |
|
||||
exists(ReturnNode ret, ValueReturnKind kind |
|
||||
c = "ReturnValue" and
|
||||
ret = node.asNode() and
|
||||
ret.getKind().(ValueReturnKind).getKind() = getStandardReturnValueKind() and
|
||||
valueReturnNode(ret, kind) and
|
||||
kind.getKind() = getStandardReturnValueKind() and
|
||||
mid.asCallable() = getNodeEnclosingCallable(ret)
|
||||
)
|
||||
or
|
||||
|
||||
Reference in New Issue
Block a user