diff --git a/ql/src/semmle/go/dataflow/FunctionInputsAndOutputs.qll b/ql/src/semmle/go/dataflow/FunctionInputsAndOutputs.qll index dd2d1d4e8..140fe260f 100644 --- a/ql/src/semmle/go/dataflow/FunctionInputsAndOutputs.qll +++ b/ql/src/semmle/go/dataflow/FunctionInputsAndOutputs.qll @@ -107,15 +107,20 @@ private class ResultInput extends FunctionInput, TInResult { } override DataFlow::Node getEntryNode(DataFlow::CallNode c) { - exists(DataFlow::PostUpdateNode pun, DataFlow::Node init | - pun = result and - init = pun.(DataFlow::SsaNode).getInit() - | + exists(DataFlow::Node pred | index = -1 and - init = c.getResult() + pred = c.getResult() or index >= 0 and - init = c.getResult(index) + pred = c.getResult(index) + | + // if the result is assigned to an SSA variable, we want to propagate mutations backwards + // through that variable + exists(DataFlow::SsaNode ssa | ssa.getInit() = pred | result = ssa) + or + // otherwise the entry node is simply the result + not exists(DataFlow::SsaNode ssa | ssa.getInit() = pred) and + result = pred ) } diff --git a/ql/test/library-tests/semmle/go/dataflow/FunctionInputsAndOutputs/FunctionInput_getEntryNode.expected b/ql/test/library-tests/semmle/go/dataflow/FunctionInputsAndOutputs/FunctionInput_getEntryNode.expected index b99d65291..8c3a2b043 100644 --- a/ql/test/library-tests/semmle/go/dataflow/FunctionInputsAndOutputs/FunctionInput_getEntryNode.expected +++ b/ql/test/library-tests/semmle/go/dataflow/FunctionInputsAndOutputs/FunctionInput_getEntryNode.expected @@ -3,6 +3,8 @@ | parameter 0 | main.go:55:2:55:27 | call to Printf | main.go:55:13:55:20 | "%d, %d" | | parameter 0 | main.go:57:2:57:27 | call to Printf | main.go:57:13:57:20 | "%d, %d" | | parameter 0 | reset.go:12:2:12:21 | call to Reset | reset.go:12:15:12:20 | source | +| parameter 0 | tst2.go:10:9:10:26 | call to NewEncoder | tst2.go:10:25:10:25 | w | +| parameter 0 | tst2.go:10:9:10:39 | call to Encode | tst2.go:10:35:10:38 | data | | parameter 0 | tst.go:10:2:10:29 | call to ReadFrom | tst.go:10:23:10:28 | reader | | parameter 0 | tst.go:16:2:16:12 | call to test5 | tst.go:16:8:16:8 | x | | parameter 0 | tst.go:18:2:18:12 | call to test5 | tst.go:18:8:18:8 | s | @@ -17,6 +19,21 @@ | parameter 2 | main.go:57:2:57:27 | call to Printf | main.go:57:26:57:26 | y | | receiver | main.go:53:14:53:21 | call to bump | main.go:53:14:53:14 | c | | receiver | reset.go:12:2:12:21 | call to Reset | reset.go:12:2:12:7 | reader | +| receiver | tst2.go:10:9:10:39 | call to Encode | tst2.go:10:9:10:26 | call to NewEncoder | | receiver | tst.go:10:2:10:29 | call to ReadFrom | tst.go:10:2:10:12 | bytesBuffer | +| result | main.go:51:2:51:14 | call to op | main.go:51:2:51:14 | call to op | +| result | main.go:53:2:53:22 | call to op2 | main.go:53:2:53:22 | call to op2 | +| result | main.go:53:14:53:21 | call to bump | main.go:53:14:53:21 | call to bump | +| result | tst2.go:10:9:10:26 | call to NewEncoder | tst2.go:10:9:10:26 | call to NewEncoder | +| result | tst2.go:10:9:10:39 | call to Encode | tst2.go:10:2:10:4 | definition of err | | result | tst.go:9:17:9:33 | call to new | tst.go:9:2:9:12 | definition of bytesBuffer | +| result 0 | main.go:51:2:51:14 | call to op | main.go:51:2:51:14 | call to op | +| result 0 | main.go:53:2:53:22 | call to op2 | main.go:53:2:53:22 | call to op2 | +| result 0 | main.go:53:14:53:21 | call to bump | main.go:53:14:53:21 | call to bump | +| result 0 | main.go:54:10:54:15 | call to test | main.go:54:2:54:2 | definition of x | +| result 0 | main.go:56:9:56:15 | call to test2 | main.go:56:2:56:2 | definition of x | +| result 0 | tst2.go:10:9:10:26 | call to NewEncoder | tst2.go:10:9:10:26 | call to NewEncoder | +| result 0 | tst2.go:10:9:10:39 | call to Encode | tst2.go:10:2:10:4 | definition of err | | result 0 | tst.go:9:17:9:33 | call to new | tst.go:9:2:9:12 | definition of bytesBuffer | +| result 1 | main.go:54:10:54:15 | call to test | main.go:54:5:54:5 | definition of y | +| result 1 | main.go:56:9:56:15 | call to test2 | main.go:56:5:56:5 | definition of y | diff --git a/ql/test/library-tests/semmle/go/dataflow/FunctionInputsAndOutputs/FunctionInput_getExitNode.expected b/ql/test/library-tests/semmle/go/dataflow/FunctionInputsAndOutputs/FunctionInput_getExitNode.expected index 3c8724021..a78fff479 100644 --- a/ql/test/library-tests/semmle/go/dataflow/FunctionInputsAndOutputs/FunctionInput_getExitNode.expected +++ b/ql/test/library-tests/semmle/go/dataflow/FunctionInputsAndOutputs/FunctionInput_getExitNode.expected @@ -2,6 +2,7 @@ | parameter 0 | main.go:13:1:20:1 | function declaration | main.go:13:10:13:11 | definition of op | | parameter 0 | main.go:40:1:48:1 | function declaration | main.go:40:12:40:12 | definition of b | | parameter 0 | reset.go:8:1:16:1 | function declaration | reset.go:8:27:8:27 | definition of r | +| parameter 0 | tst2.go:8:1:12:1 | function declaration | tst2.go:8:12:8:15 | definition of data | | parameter 0 | tst.go:8:1:11:1 | function declaration | tst.go:8:12:8:17 | definition of reader | | parameter 0 | tst.go:15:1:19:1 | function declaration | tst.go:15:12:15:12 | definition of x | | parameter 1 | main.go:5:1:11:1 | function declaration | main.go:5:20:5:20 | definition of x | diff --git a/ql/test/library-tests/semmle/go/dataflow/FunctionInputsAndOutputs/FunctionModelStep.expected b/ql/test/library-tests/semmle/go/dataflow/FunctionInputsAndOutputs/FunctionModelStep.expected index be1c46b34..80f34d73d 100644 --- a/ql/test/library-tests/semmle/go/dataflow/FunctionInputsAndOutputs/FunctionModelStep.expected +++ b/ql/test/library-tests/semmle/go/dataflow/FunctionInputsAndOutputs/FunctionModelStep.expected @@ -1,2 +1,4 @@ +| file://:0:0:0:0 | Encode | tst2.go:10:35:10:38 | data | tst2.go:10:9:10:26 | call to NewEncoder | +| file://:0:0:0:0 | NewEncoder | tst2.go:10:9:10:26 | call to NewEncoder | tst2.go:9:6:9:6 | definition of w | | file://:0:0:0:0 | ReadFrom | tst.go:10:23:10:28 | reader | tst.go:9:2:9:12 | definition of bytesBuffer | | file://:0:0:0:0 | Reset | reset.go:12:15:12:20 | source | reset.go:11:6:11:11 | definition of reader | diff --git a/ql/test/library-tests/semmle/go/dataflow/FunctionInputsAndOutputs/FunctionOutput_getEntryNode.expected b/ql/test/library-tests/semmle/go/dataflow/FunctionInputsAndOutputs/FunctionOutput_getEntryNode.expected index 174584199..263a92984 100644 --- a/ql/test/library-tests/semmle/go/dataflow/FunctionInputsAndOutputs/FunctionOutput_getEntryNode.expected +++ b/ql/test/library-tests/semmle/go/dataflow/FunctionInputsAndOutputs/FunctionOutput_getEntryNode.expected @@ -11,6 +11,7 @@ | result 0 | main.go:40:1:48:1 | function declaration | main.go:40:21:40:23 | zero value for int | | result 0 | main.go:40:1:48:1 | function declaration | main.go:45:10:45:10 | 0 | | result 0 | main.go:40:1:48:1 | function declaration | main.go:47:9:47:9 | 0 | +| result 0 | tst2.go:8:1:12:1 | function declaration | tst2.go:11:9:11:9 | w | | result 1 | main.go:31:1:33:1 | function declaration | main.go:32:13:32:14 | 42 | | result 1 | main.go:35:1:38:1 | function declaration | main.go:35:22:35:22 | zero value for y | | result 1 | main.go:35:1:38:1 | function declaration | main.go:36:9:36:10 | 42 | @@ -18,3 +19,4 @@ | result 1 | main.go:40:1:48:1 | function declaration | main.go:42:3:42:5 | rhs of increment statement | | result 1 | main.go:40:1:48:1 | function declaration | main.go:45:13:45:13 | 1 | | result 1 | main.go:40:1:48:1 | function declaration | main.go:47:12:47:12 | 4 | +| result 1 | tst2.go:8:1:12:1 | function declaration | tst2.go:11:12:11:14 | err | diff --git a/ql/test/library-tests/semmle/go/dataflow/FunctionInputsAndOutputs/FunctionOutput_getExitNode.expected b/ql/test/library-tests/semmle/go/dataflow/FunctionInputsAndOutputs/FunctionOutput_getExitNode.expected index 29aba9aef..e8addfb21 100644 --- a/ql/test/library-tests/semmle/go/dataflow/FunctionInputsAndOutputs/FunctionOutput_getExitNode.expected +++ b/ql/test/library-tests/semmle/go/dataflow/FunctionInputsAndOutputs/FunctionOutput_getExitNode.expected @@ -1,19 +1,26 @@ | parameter 0 | reset.go:12:2:12:21 | call to Reset | reset.go:9:2:9:7 | definition of source | +| parameter 0 | tst2.go:10:9:10:26 | call to NewEncoder | tst2.go:9:6:9:6 | definition of w | +| parameter 0 | tst2.go:10:9:10:39 | call to Encode | tst2.go:8:12:8:15 | definition of data | | parameter 0 | tst.go:10:2:10:29 | call to ReadFrom | tst.go:8:12:8:17 | definition of reader | | parameter 0 | tst.go:16:2:16:12 | call to test5 | tst.go:15:12:15:12 | definition of x | | parameter 1 | tst.go:16:2:16:12 | call to test5 | tst.go:15:15:15:15 | definition of y | | receiver | main.go:53:14:53:21 | call to bump | main.go:52:2:52:2 | definition of c | | receiver | reset.go:12:2:12:21 | call to Reset | reset.go:11:6:11:11 | definition of reader | +| receiver | tst2.go:10:9:10:39 | call to Encode | tst2.go:10:9:10:26 | call to NewEncoder | | receiver | tst.go:10:2:10:29 | call to ReadFrom | tst.go:9:2:9:12 | definition of bytesBuffer | | result | main.go:51:2:51:14 | call to op | main.go:51:2:51:14 | call to op | | result | main.go:53:2:53:22 | call to op2 | main.go:53:2:53:22 | call to op2 | | result | main.go:53:14:53:21 | call to bump | main.go:53:14:53:21 | call to bump | +| result | tst2.go:10:9:10:26 | call to NewEncoder | tst2.go:10:9:10:26 | call to NewEncoder | +| result | tst2.go:10:9:10:39 | call to Encode | tst2.go:10:9:10:39 | call to Encode | | result | tst.go:9:17:9:33 | call to new | tst.go:9:17:9:33 | call to new | | result 0 | main.go:51:2:51:14 | call to op | main.go:51:2:51:14 | call to op | | result 0 | main.go:53:2:53:22 | call to op2 | main.go:53:2:53:22 | call to op2 | | result 0 | main.go:53:14:53:21 | call to bump | main.go:53:14:53:21 | call to bump | | result 0 | main.go:54:10:54:15 | call to test | main.go:54:2:54:15 | ... := ...[0] | | result 0 | main.go:56:9:56:15 | call to test2 | main.go:56:2:56:15 | ... = ...[0] | +| result 0 | tst2.go:10:9:10:26 | call to NewEncoder | tst2.go:10:9:10:26 | call to NewEncoder | +| result 0 | tst2.go:10:9:10:39 | call to Encode | tst2.go:10:9:10:39 | call to Encode | | result 0 | tst.go:9:17:9:33 | call to new | tst.go:9:17:9:33 | call to new | | result 1 | main.go:54:10:54:15 | call to test | main.go:54:2:54:15 | ... := ...[1] | | result 1 | main.go:56:9:56:15 | call to test2 | main.go:56:2:56:15 | ... = ...[1] | diff --git a/ql/test/library-tests/semmle/go/dataflow/FunctionInputsAndOutputs/FunctionOutput_isResult.expected b/ql/test/library-tests/semmle/go/dataflow/FunctionInputsAndOutputs/FunctionOutput_isResult.expected index 7f903e4ef..227c9cb59 100644 --- a/ql/test/library-tests/semmle/go/dataflow/FunctionInputsAndOutputs/FunctionOutput_isResult.expected +++ b/ql/test/library-tests/semmle/go/dataflow/FunctionInputsAndOutputs/FunctionOutput_isResult.expected @@ -1,4 +1,6 @@ | main.go:51:2:51:14 | call to op | main.go:51:2:51:14 | call to op | result | | main.go:53:2:53:22 | call to op2 | main.go:53:2:53:22 | call to op2 | result | | main.go:53:14:53:21 | call to bump | main.go:53:14:53:21 | call to bump | result | +| tst2.go:10:9:10:26 | call to NewEncoder | tst2.go:10:9:10:26 | call to NewEncoder | result | +| tst2.go:10:9:10:39 | call to Encode | tst2.go:10:9:10:39 | call to Encode | result | | tst.go:9:17:9:33 | call to new | tst.go:9:17:9:33 | call to new | result | diff --git a/ql/test/library-tests/semmle/go/dataflow/FunctionInputsAndOutputs/FunctionOutput_isResult_int.expected b/ql/test/library-tests/semmle/go/dataflow/FunctionInputsAndOutputs/FunctionOutput_isResult_int.expected index 06c5efaea..61f029031 100644 --- a/ql/test/library-tests/semmle/go/dataflow/FunctionInputsAndOutputs/FunctionOutput_isResult_int.expected +++ b/ql/test/library-tests/semmle/go/dataflow/FunctionInputsAndOutputs/FunctionOutput_isResult_int.expected @@ -8,5 +8,9 @@ | main.go:54:10:54:15 | call to test | main.go:54:2:54:15 | ... := ...[1] | 1 | result 1 | | main.go:56:9:56:15 | call to test2 | main.go:56:2:56:15 | ... = ...[0] | 0 | result 0 | | main.go:56:9:56:15 | call to test2 | main.go:56:2:56:15 | ... = ...[1] | 1 | result 1 | +| tst2.go:10:9:10:26 | call to NewEncoder | tst2.go:10:9:10:26 | call to NewEncoder | 0 | result | +| tst2.go:10:9:10:26 | call to NewEncoder | tst2.go:10:9:10:26 | call to NewEncoder | 0 | result 0 | +| tst2.go:10:9:10:39 | call to Encode | tst2.go:10:9:10:39 | call to Encode | 0 | result | +| tst2.go:10:9:10:39 | call to Encode | tst2.go:10:9:10:39 | call to Encode | 0 | result 0 | | tst.go:9:17:9:33 | call to new | tst.go:9:17:9:33 | call to new | 0 | result | | tst.go:9:17:9:33 | call to new | tst.go:9:17:9:33 | call to new | 0 | result 0 | diff --git a/ql/test/library-tests/semmle/go/dataflow/FunctionInputsAndOutputs/tst2.go b/ql/test/library-tests/semmle/go/dataflow/FunctionInputsAndOutputs/tst2.go new file mode 100644 index 000000000..4bfe9246c --- /dev/null +++ b/ql/test/library-tests/semmle/go/dataflow/FunctionInputsAndOutputs/tst2.go @@ -0,0 +1,12 @@ +package main + +import ( + "encoding/json" + "io" +) + +func test7(data interface{}) (io.Writer, error) { + var w io.Writer + err := json.NewEncoder(w).Encode(data) + return w, err +}