Skip to content

Commit 4d8ca3d

Browse files
committed
Add dataflow callback to filter out receiver argument flow to Golang interface dispatch candidates.
Other langauges stub the callback.
1 parent 7ffe863 commit 4d8ca3d

File tree

17 files changed

+108
-16
lines changed

17 files changed

+108
-16
lines changed

cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowDispatch.qll

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,3 +79,11 @@ class ArgumentPosition extends int {
7979
/** Holds if arguments at position `apos` match parameters at position `ppos`. */
8080
pragma[inline]
8181
predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) { ppos = apos }
82+
83+
/**
84+
* Holds if flow from `call`'s argument `arg` to parameter `p` is permissible.
85+
*
86+
* This is a filter on top of the language-neutral argument/parameter matching implemented by `viableParamArg`.
87+
*/
88+
pragma[inline]
89+
predicate viableParamArgSpecific(DataFlowCall call, ParameterNode p, ArgumentNode arg) { any() }

cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -425,7 +425,8 @@ private module Cached {
425425
exists(ParameterPosition ppos |
426426
viableParam(call, ppos, p) and
427427
argumentPositionMatch(call, arg, ppos) and
428-
compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(p))
428+
compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(p)) and
429+
viableParamArgSpecific(call, p, arg)
429430
)
430431
}
431432

cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowDispatch.qll

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,3 +271,11 @@ Function viableImplInCallContext(CallInstruction call, CallInstruction ctx) {
271271
/** Holds if arguments at position `apos` match parameters at position `ppos`. */
272272
pragma[inline]
273273
predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) { ppos = apos }
274+
275+
/**
276+
* Holds if flow from `call`'s argument `arg` to parameter `p` is permissible.
277+
*
278+
* This is a filter on top of the language-neutral argument/parameter matching implemented by `viableParamArg`.
279+
*/
280+
pragma[inline]
281+
predicate viableParamArgSpecific(DataFlowCall call, ParameterNode p, ArgumentNode arg) { any() }

cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -425,7 +425,8 @@ private module Cached {
425425
exists(ParameterPosition ppos |
426426
viableParam(call, ppos, p) and
427427
argumentPositionMatch(call, arg, ppos) and
428-
compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(p))
428+
compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(p)) and
429+
viableParamArgSpecific(call, p, arg)
429430
)
430431
}
431432

csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -555,3 +555,11 @@ predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) {
555555
apos.isImplicitCapturedArgumentPosition(v)
556556
)
557557
}
558+
559+
/**
560+
* Holds if flow from `call`'s argument `arg` to parameter `p` is permissible.
561+
*
562+
* This is a filter on top of the language-neutral argument/parameter matching implemented by `viableParamArg`.
563+
*/
564+
pragma[inline]
565+
predicate viableParamArgSpecific(DataFlowCall call, ParameterNode p, ArgumentNode arg) { any() }

csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -425,7 +425,8 @@ private module Cached {
425425
exists(ParameterPosition ppos |
426426
viableParam(call, ppos, p) and
427427
argumentPositionMatch(call, arg, ppos) and
428-
compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(p))
428+
compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(p)) and
429+
viableParamArgSpecific(call, p, arg)
429430
)
430431
}
431432

go/ql/lib/semmle/go/dataflow/internal/DataFlowDispatch.qll

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,3 +133,25 @@ class ArgumentPosition extends int {
133133
/** Holds if arguments at position `apos` match parameters at position `ppos`. */
134134
pragma[inline]
135135
predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) { ppos = apos }
136+
137+
private predicate isInterfaceMethod(Method c) {
138+
c.getReceiverBaseType().getUnderlyingType() instanceof InterfaceType
139+
}
140+
141+
/**
142+
* Holds if `call` is passing `arg` to param `p` in any circumstance except passing
143+
* a receiver parameter to a concrete method.
144+
*/
145+
pragma[inline]
146+
predicate viableParamArgSpecific(
147+
DataFlowCall call, DataFlow::ParameterNode p, DataFlow::ArgumentNode arg
148+
) {
149+
// Interface methods calls may be passed strictly to that exact method's model receiver:
150+
arg.getPosition() != -1
151+
or
152+
exists(Function callTarget | callTarget = call.getNode().(DataFlow::CallNode).getTarget() |
153+
not isInterfaceMethod(callTarget)
154+
or
155+
callTarget = p.getCallable().asSummarizedCallable().asFunction()
156+
)
157+
}

go/ql/lib/semmle/go/dataflow/internal/DataFlowImplCommon.qll

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -425,7 +425,8 @@ private module Cached {
425425
exists(ParameterPosition ppos |
426426
viableParam(call, ppos, p) and
427427
argumentPositionMatch(call, arg, ppos) and
428-
compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(p))
428+
compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(p)) and
429+
viableParamArgSpecific(call, p, arg)
429430
)
430431
}
431432

go/ql/lib/semmle/go/dataflow/internal/DataFlowNodes.qll

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -570,6 +570,12 @@ module Public {
570570
abstract class ParameterNode extends DataFlow::Node {
571571
/** Holds if this node initializes the `i`th parameter of `c`. */
572572
abstract predicate isParameterOf(DataFlowCallable c, int i);
573+
574+
/** Gets the callable that this parameter belongs to. */
575+
DataFlowCallable getCallable() { this.isParameterOf(result, _) }
576+
577+
/** Gets this parameter's position. */
578+
int getPosition() { this.isParameterOf(_, result) }
573579
}
574580

575581
/**
@@ -722,20 +728,18 @@ module Public {
722728
*/
723729
predicate argumentOf(CallExpr call, int pos) {
724730
call = c.asExpr() and
725-
pos = i and
726-
(
727-
i != -1
728-
or
729-
exists(c.(MethodCallNode).getTarget().getBody())
730-
or
731-
hasExternalSpecification(c.(DataFlow::MethodCallNode).getTarget())
732-
)
731+
pos = i
733732
}
734733

735734
/**
736735
* Gets the `CallNode` this is an argument to.
737736
*/
738737
CallNode getCall() { result = c }
738+
739+
/**
740+
* Gets this argument's position.
741+
*/
742+
int getPosition() { result = i }
739743
}
740744

741745
/**

java/ql/lib/semmle/code/java/dataflow/internal/DataFlowDispatch.qll

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,14 @@ private module DispatchImpl {
171171
/** Holds if arguments at position `apos` match parameters at position `ppos`. */
172172
pragma[inline]
173173
predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) { ppos = apos }
174+
175+
/**
176+
* Holds if flow from `call`'s argument `arg` to parameter `p` is permissible.
177+
*
178+
* This is a filter on top of the language-neutral argument/parameter matching implemented by `viableParamArg`.
179+
*/
180+
pragma[inline]
181+
predicate viableParamArgSpecific(DataFlowCall call, ParameterNode p, ArgumentNode arg) { any() }
174182
}
175183

176184
import DispatchImpl

0 commit comments

Comments
 (0)