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`. */
|
/** Holds if arguments at position `apos` match parameters at position `ppos`. */
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) { ppos = apos }
|
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 |
|
exists(ParameterPosition ppos |
|
||||||
viableParam(call, ppos, p) and
|
viableParam(call, ppos, p) and
|
||||||
argumentPositionMatch(call, arg, ppos) 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`. */
|
/** Holds if arguments at position `apos` match parameters at position `ppos`. */
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) { ppos = apos }
|
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 |
|
exists(ParameterPosition ppos |
|
||||||
viableParam(call, ppos, p) and
|
viableParam(call, ppos, p) and
|
||||||
argumentPositionMatch(call, arg, ppos) 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)
|
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 |
|
exists(ParameterPosition ppos |
|
||||||
viableParam(call, ppos, p) and
|
viableParam(call, ppos, p) and
|
||||||
argumentPositionMatch(call, arg, ppos) 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`. */
|
/** Holds if arguments at position `apos` match parameters at position `ppos`. */
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) { ppos = apos }
|
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 |
|
exists(ParameterPosition ppos |
|
||||||
viableParam(call, ppos, p) and
|
viableParam(call, ppos, p) and
|
||||||
argumentPositionMatch(call, arg, ppos) 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 {
|
abstract class ParameterNode extends DataFlow::Node {
|
||||||
/** Holds if this node initializes the `i`th parameter of `c`. */
|
/** Holds if this node initializes the `i`th parameter of `c`. */
|
||||||
abstract predicate isParameterOf(DataFlowCallable c, int i);
|
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) {
|
predicate argumentOf(CallExpr call, int pos) {
|
||||||
call = c.asExpr() and
|
call = c.asExpr() and
|
||||||
pos = i and
|
pos = i
|
||||||
(
|
|
||||||
i != -1
|
|
||||||
or
|
|
||||||
exists(c.(MethodCallNode).getTarget().getBody())
|
|
||||||
or
|
|
||||||
hasExternalSpecification(c.(DataFlow::MethodCallNode).getTarget())
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the `CallNode` this is an argument to.
|
* Gets the `CallNode` this is an argument to.
|
||||||
*/
|
*/
|
||||||
CallNode getCall() { result = c }
|
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`. */
|
/** Holds if arguments at position `apos` match parameters at position `ppos`. */
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) { ppos = apos }
|
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
|
import DispatchImpl
|
||||||
|
|||||||
@@ -425,7 +425,8 @@ private module Cached {
|
|||||||
exists(ParameterPosition ppos |
|
exists(ParameterPosition ppos |
|
||||||
viableParam(call, ppos, p) and
|
viableParam(call, ppos, p) and
|
||||||
argumentPositionMatch(call, arg, ppos) 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`.
|
* `kind`.
|
||||||
*/
|
*/
|
||||||
OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) { call = result.getCall(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 |
|
exists(ParameterPosition ppos |
|
||||||
viableParam(call, ppos, p) and
|
viableParam(call, ppos, p) and
|
||||||
argumentPositionMatch(call, arg, ppos) 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
|
or
|
||||||
apos.isAnyNamed() and ppos.isKeyword(_)
|
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 |
|
exists(ParameterPosition ppos |
|
||||||
viableParam(call, ppos, p) and
|
viableParam(call, ppos, p) and
|
||||||
argumentPositionMatch(call, arg, ppos) 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
|
or
|
||||||
ppos.(PositionalParameterPosition).getIndex() = apos.(PositionalArgumentPosition).getIndex()
|
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 |
|
exists(ParameterPosition ppos |
|
||||||
viableParam(call, ppos, p) and
|
viableParam(call, ppos, p) and
|
||||||
argumentPositionMatch(call, arg, ppos) 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