diff --git a/ql/lib/semmle/go/Scopes.qll b/ql/lib/semmle/go/Scopes.qll index 91ac579b4..172156a0c 100644 --- a/ql/lib/semmle/go/Scopes.qll +++ b/ql/lib/semmle/go/Scopes.qll @@ -620,6 +620,9 @@ class Callable extends TCallable { result = this.asFuncLit().getType() } + /** Holds if this callable is variadic. */ + predicate isVariadic() { this.getType().isVariadic() } + /** Gets the name of this callable. */ string getName() { result = this.asFunction().getName() or diff --git a/ql/lib/semmle/go/dataflow/internal/ContainerFlow.qll b/ql/lib/semmle/go/dataflow/internal/ContainerFlow.qll index b6c1005da..177c5e854 100644 --- a/ql/lib/semmle/go/dataflow/internal/ContainerFlow.qll +++ b/ql/lib/semmle/go/dataflow/internal/ContainerFlow.qll @@ -16,6 +16,14 @@ private import semmle.go.dataflow.ExternalFlow predicate containerStoreStep(Node node1, Node node2, Content c) { c instanceof ArrayContent and ( + exists(ArgumentNode arg, ParameterNode parm, Callable fn | + arg = node1 and + parm = node2 and + arg.getCall().getACalleeIncludingExternals() = fn and + arg.isVariadic() and + parm.isParameterOf(fn, fn.getType().getNumParameter() - 1) = arg.getCall() + ) + or ( node2.getType() instanceof ArrayType or node2.getType() instanceof SliceType diff --git a/ql/lib/semmle/go/dataflow/internal/DataFlowNodes.qll b/ql/lib/semmle/go/dataflow/internal/DataFlowNodes.qll index a8453792f..f7e1a7ebd 100644 --- a/ql/lib/semmle/go/dataflow/internal/DataFlowNodes.qll +++ b/ql/lib/semmle/go/dataflow/internal/DataFlowNodes.qll @@ -542,6 +542,9 @@ module Public { /** Gets the data flow node corresponding to the receiver of this call, if any. */ Node getReceiver() { result = this.getACalleeSource().(MethodReadNode).getReceiver() } + /** Holds if this callee calls a callable that is variadic. */ + predicate isVariadic() { this.getACalleeIncludingExternals().isVariadic() } + /** Holds if this call has an ellipsis after its last argument. */ predicate hasEllipsis() { expr.hasEllipsis() } } @@ -714,6 +717,12 @@ module Public { ) } + /** Holds if this argument is to a call that has a variadic callee. */ + predicate isVariadic() { + this.getCall().isVariadic() and + i >= this.getCall().getACalleeIncludingExternals().getType().getNumParameter() - 1 + } + /** * Gets the `CallNode` this is an argument to. */