Skip to content

Commit 73b712a

Browse files
committed
Allow data flow through varargs parameters
1 parent b47c8e8 commit 73b712a

File tree

3 files changed

+54
-2
lines changed

3 files changed

+54
-2
lines changed

go/ql/lib/semmle/go/Expr.qll

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -857,6 +857,18 @@ class CallExpr extends CallOrConversionExpr {
857857
/** Gets the number of argument expressions of this call. */
858858
int getNumArgument() { result = count(this.getAnArgument()) }
859859

860+
/**
861+
* Gets an argument with an ellipsis after it which is passed to a varargs
862+
* parameter, as in `f(x...)`.
863+
*
864+
* Note that if the varargs parameter is `...T` then the type of the argument
865+
* must be assignable to the slice type `[]T`.
866+
*/
867+
Expr getExplicitVarargsArgument() {
868+
this.hasEllipsis() and
869+
result = this.getArgument(this.getNumArgument() - 1)
870+
}
871+
860872
/**
861873
* Gets the name of the invoked function, method or variable if it can be
862874
* determined syntactically.

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ private import semmle.go.dataflow.ExternalFlow
1010
* Holds if the step from `node1` to `node2` stores a value in an array, a
1111
* slice, a collection or a map. Thus, `node2` references an object with a
1212
* content `c` that contains the value of `node1`. This covers array
13-
* assignments and initializers as well as implicit array creations for
13+
* assignments and initializers as well as implicit slice creations for
1414
* varargs.
1515
*/
1616
predicate containerStoreStep(Node node1, Node node2, Content c) {
@@ -20,7 +20,11 @@ predicate containerStoreStep(Node node1, Node node2, Content c) {
2020
node2.getType() instanceof ArrayType or
2121
node2.getType() instanceof SliceType
2222
) and
23-
exists(Write w | w.writesElement(node2, _, node1))
23+
(
24+
exists(Write w | w.writesElement(node2, _, node1))
25+
or
26+
node1 = node2.(ImplicitVarargsSlice).getCallNode().getImplicitVarargsArgument(_)
27+
)
2428
)
2529
or
2630
c instanceof CollectionContent and

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

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ private newtype TNode =
1010
MkInstructionNode(IR::Instruction insn) or
1111
MkSsaNode(SsaDefinition ssa) or
1212
MkGlobalFunctionNode(Function f) or
13+
MkImplicitVarargsSlice(CallExpr c) { c.getTarget().isVariadic() and not c.hasEllipsis() } or
1314
MkSummarizedParameterNode(SummarizedCallable c, int i) {
1415
FlowSummaryImpl::Private::summaryParameterNodeRange(c, i)
1516
} or
@@ -426,6 +427,41 @@ module Public {
426427
override ResultNode getAResult() { result.getRoot() = this.getExpr() }
427428
}
428429

430+
/**
431+
* An implicit varargs slice creation expression.
432+
*
433+
* A variadic function like `f(t1 T1, ..., Tm tm, A... x)` actually sees the
434+
* varargs parameter as a slice `[]A`. A call `f(t1, ..., tm, x1, ..., xn)`
435+
* desugars to `f(t1, ..., tm, []A{x1, ..., xn})`, and this node corresponds
436+
* to this implicit slice creation.
437+
*/
438+
class ImplicitVarargsSlice extends Node, MkImplicitVarargsSlice {
439+
CallNode call;
440+
441+
ImplicitVarargsSlice() { this = MkImplicitVarargsSlice(call.getCall()) }
442+
443+
override ControlFlow::Root getRoot() { result = call.getRoot() }
444+
445+
/** Gets the call containing this varargs slice creation argument. */
446+
CallNode getCallNode() { result = call }
447+
448+
override Type getType() {
449+
exists(Function f | f = call.getTarget() |
450+
result = f.getParameterType(f.getNumParameter() - 1)
451+
)
452+
}
453+
454+
override string getNodeKind() { result = "implicit varargs slice" }
455+
456+
override string toString() { result = "[]type{args}" }
457+
458+
override predicate hasLocationInfo(
459+
string filepath, int startline, int startcolumn, int endline, int endcolumn
460+
) {
461+
call.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
462+
}
463+
}
464+
429465
/**
430466
* Gets a possible target of call `cn`.class
431467
*

0 commit comments

Comments
 (0)