Data flow: Synthesize parameter return nodes

This commit is contained in:
Tom Hvitved
2024-05-02 10:06:58 +02:00
parent 358c7410c8
commit 454687d583
9 changed files with 198 additions and 113 deletions

View File

@@ -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)
)
}

View File

@@ -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)
)
}

View File

@@ -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()
}

View File

@@ -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

View File

@@ -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)
)
}

View File

@@ -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()
}

View File

@@ -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

View File

@@ -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. */

View File

@@ -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