mirror of
https://github.com/github/codeql.git
synced 2025-12-24 04:36:35 +01:00
Add dataflow callback to filter out receiver argument flow to Golang interface dispatch candidates.
Other langauges stub the callback.
This commit is contained in:
@@ -79,3 +79,11 @@ class ArgumentPosition extends int {
|
||||
/** Holds if arguments at position `apos` match parameters at position `ppos`. */
|
||||
pragma[inline]
|
||||
predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) { ppos = apos }
|
||||
|
||||
/**
|
||||
* Holds if flow from `call`'s argument `arg` to parameter `p` is permissible.
|
||||
*
|
||||
* This is a filter on top of the language-neutral argument/parameter matching implemented by `viableParamArg`.
|
||||
*/
|
||||
pragma[inline]
|
||||
predicate viableParamArgSpecific(DataFlowCall call, ParameterNode p, ArgumentNode arg) { any() }
|
||||
|
||||
@@ -425,7 +425,8 @@ private module Cached {
|
||||
exists(ParameterPosition ppos |
|
||||
viableParam(call, ppos, p) and
|
||||
argumentPositionMatch(call, arg, ppos) and
|
||||
compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(p))
|
||||
compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(p)) and
|
||||
viableParamArgSpecific(call, p, arg)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -271,3 +271,11 @@ Function viableImplInCallContext(CallInstruction call, CallInstruction ctx) {
|
||||
/** Holds if arguments at position `apos` match parameters at position `ppos`. */
|
||||
pragma[inline]
|
||||
predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) { ppos = apos }
|
||||
|
||||
/**
|
||||
* Holds if flow from `call`'s argument `arg` to parameter `p` is permissible.
|
||||
*
|
||||
* This is a filter on top of the language-neutral argument/parameter matching implemented by `viableParamArg`.
|
||||
*/
|
||||
pragma[inline]
|
||||
predicate viableParamArgSpecific(DataFlowCall call, ParameterNode p, ArgumentNode arg) { any() }
|
||||
|
||||
@@ -425,7 +425,8 @@ private module Cached {
|
||||
exists(ParameterPosition ppos |
|
||||
viableParam(call, ppos, p) and
|
||||
argumentPositionMatch(call, arg, ppos) and
|
||||
compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(p))
|
||||
compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(p)) and
|
||||
viableParamArgSpecific(call, p, arg)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -555,3 +555,11 @@ predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) {
|
||||
apos.isImplicitCapturedArgumentPosition(v)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if flow from `call`'s argument `arg` to parameter `p` is permissible.
|
||||
*
|
||||
* This is a filter on top of the language-neutral argument/parameter matching implemented by `viableParamArg`.
|
||||
*/
|
||||
pragma[inline]
|
||||
predicate viableParamArgSpecific(DataFlowCall call, ParameterNode p, ArgumentNode arg) { any() }
|
||||
|
||||
@@ -425,7 +425,8 @@ private module Cached {
|
||||
exists(ParameterPosition ppos |
|
||||
viableParam(call, ppos, p) and
|
||||
argumentPositionMatch(call, arg, ppos) and
|
||||
compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(p))
|
||||
compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(p)) and
|
||||
viableParamArgSpecific(call, p, arg)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -133,3 +133,25 @@ class ArgumentPosition extends int {
|
||||
/** Holds if arguments at position `apos` match parameters at position `ppos`. */
|
||||
pragma[inline]
|
||||
predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) { ppos = apos }
|
||||
|
||||
private predicate isInterfaceMethod(Method c) {
|
||||
c.getReceiverBaseType().getUnderlyingType() instanceof InterfaceType
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `call` is passing `arg` to param `p` in any circumstance except passing
|
||||
* a receiver parameter to a concrete method.
|
||||
*/
|
||||
pragma[inline]
|
||||
predicate viableParamArgSpecific(
|
||||
DataFlowCall call, DataFlow::ParameterNode p, DataFlow::ArgumentNode arg
|
||||
) {
|
||||
// Interface methods calls may be passed strictly to that exact method's model receiver:
|
||||
arg.getPosition() != -1
|
||||
or
|
||||
exists(Function callTarget | callTarget = call.getNode().(DataFlow::CallNode).getTarget() |
|
||||
not isInterfaceMethod(callTarget)
|
||||
or
|
||||
callTarget = p.getCallable().asSummarizedCallable().asFunction()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -425,7 +425,8 @@ private module Cached {
|
||||
exists(ParameterPosition ppos |
|
||||
viableParam(call, ppos, p) and
|
||||
argumentPositionMatch(call, arg, ppos) and
|
||||
compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(p))
|
||||
compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(p)) and
|
||||
viableParamArgSpecific(call, p, arg)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -570,6 +570,12 @@ module Public {
|
||||
abstract class ParameterNode extends DataFlow::Node {
|
||||
/** Holds if this node initializes the `i`th parameter of `c`. */
|
||||
abstract predicate isParameterOf(DataFlowCallable c, int i);
|
||||
|
||||
/** Gets the callable that this parameter belongs to. */
|
||||
DataFlowCallable getCallable() { this.isParameterOf(result, _) }
|
||||
|
||||
/** Gets this parameter's position. */
|
||||
int getPosition() { this.isParameterOf(_, result) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -722,20 +728,18 @@ module Public {
|
||||
*/
|
||||
predicate argumentOf(CallExpr call, int pos) {
|
||||
call = c.asExpr() and
|
||||
pos = i and
|
||||
(
|
||||
i != -1
|
||||
or
|
||||
exists(c.(MethodCallNode).getTarget().getBody())
|
||||
or
|
||||
hasExternalSpecification(c.(DataFlow::MethodCallNode).getTarget())
|
||||
)
|
||||
pos = i
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `CallNode` this is an argument to.
|
||||
*/
|
||||
CallNode getCall() { result = c }
|
||||
|
||||
/**
|
||||
* Gets this argument's position.
|
||||
*/
|
||||
int getPosition() { result = i }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -171,6 +171,14 @@ private module DispatchImpl {
|
||||
/** Holds if arguments at position `apos` match parameters at position `ppos`. */
|
||||
pragma[inline]
|
||||
predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) { ppos = apos }
|
||||
|
||||
/**
|
||||
* Holds if flow from `call`'s argument `arg` to parameter `p` is permissible.
|
||||
*
|
||||
* This is a filter on top of the language-neutral argument/parameter matching implemented by `viableParamArg`.
|
||||
*/
|
||||
pragma[inline]
|
||||
predicate viableParamArgSpecific(DataFlowCall call, ParameterNode p, ArgumentNode arg) { any() }
|
||||
}
|
||||
|
||||
import DispatchImpl
|
||||
|
||||
@@ -425,7 +425,8 @@ private module Cached {
|
||||
exists(ParameterPosition ppos |
|
||||
viableParam(call, ppos, p) and
|
||||
argumentPositionMatch(call, arg, ppos) and
|
||||
compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(p))
|
||||
compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(p)) and
|
||||
viableParamArgSpecific(call, p, arg)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1614,3 +1614,11 @@ private module OutNodes {
|
||||
* `kind`.
|
||||
*/
|
||||
OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) { call = result.getCall(kind) }
|
||||
|
||||
/**
|
||||
* Holds if flow from `call`'s argument `arg` to parameter `p` is permissible.
|
||||
*
|
||||
* This is a filter on top of the language-neutral argument/parameter matching implemented by `viableParamArg`.
|
||||
*/
|
||||
pragma[inline]
|
||||
predicate viableParamArgSpecific(DataFlowCall call, ParameterNode p, ArgumentNode arg) { any() }
|
||||
|
||||
@@ -425,7 +425,8 @@ private module Cached {
|
||||
exists(ParameterPosition ppos |
|
||||
viableParam(call, ppos, p) and
|
||||
argumentPositionMatch(call, arg, ppos) and
|
||||
compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(p))
|
||||
compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(p)) and
|
||||
viableParamArgSpecific(call, p, arg)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1380,3 +1380,13 @@ predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) {
|
||||
or
|
||||
apos.isAnyNamed() and ppos.isKeyword(_)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if flow from `call`'s argument `arg` to parameter `p` is permissible.
|
||||
*
|
||||
* This is a filter on top of the language-neutral argument/parameter matching implemented by `viableParamArg`.
|
||||
*/
|
||||
pragma[inline]
|
||||
predicate viableParamArgSpecific(DataFlowCall call, DataFlow::Node param, ArgumentNode arg) {
|
||||
any()
|
||||
}
|
||||
|
||||
@@ -425,7 +425,8 @@ private module Cached {
|
||||
exists(ParameterPosition ppos |
|
||||
viableParam(call, ppos, p) and
|
||||
argumentPositionMatch(call, arg, ppos) and
|
||||
compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(p))
|
||||
compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(p)) and
|
||||
viableParamArgSpecific(call, p, arg)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -333,3 +333,11 @@ predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) {
|
||||
or
|
||||
ppos.(PositionalParameterPosition).getIndex() = apos.(PositionalArgumentPosition).getIndex()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if flow from `call`'s argument `arg` to parameter `p` is permissible.
|
||||
*
|
||||
* This is a filter on top of the language-neutral argument/parameter matching implemented by `viableParamArg`.
|
||||
*/
|
||||
pragma[inline]
|
||||
predicate viableParamArgSpecific(DataFlowCall call, ParameterNode p, ArgumentNode arg) { any() }
|
||||
|
||||
@@ -425,7 +425,8 @@ private module Cached {
|
||||
exists(ParameterPosition ppos |
|
||||
viableParam(call, ppos, p) and
|
||||
argumentPositionMatch(call, arg, ppos) and
|
||||
compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(p))
|
||||
compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(p)) and
|
||||
viableParamArgSpecific(call, p, arg)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user