Skip to content
This repository was archived by the owner on Jan 5, 2023. It is now read-only.

Commit b37bdec

Browse files
authored
Merge pull request #157 from owen-mc/isresult-consistency
Make FunctionOutput.isResult(0) and CallNode.getResult(0) match single results
2 parents 2f7ff6b + 36fa2c2 commit b37bdec

20 files changed

Lines changed: 94 additions & 44 deletions

ql/src/experimental/frameworks/Gin.qll

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,6 @@ private module Gin {
7272
)
7373
|
7474
this = call.getResult(0)
75-
or
76-
this = call.getResult()
7775
)
7876
or
7977
// Field reads:
@@ -104,8 +102,6 @@ private module Gin {
104102
call.getTarget().hasQualifiedName(packagePath, typeName, ["ByName", "Get"])
105103
|
106104
this = call.getResult(0)
107-
or
108-
this = call.getResult()
109105
)
110106
)
111107
}

ql/src/semmle/go/dataflow/FunctionInputsAndOutputs.qll

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,11 @@ private class ResultInput extends FunctionInput, TInResult {
100100

101101
override predicate isResult() { index = -1 }
102102

103-
override predicate isResult(int i) { i = index and i >= 0 }
103+
override predicate isResult(int i) {
104+
i = 0 and isResult()
105+
or
106+
i = index and i >= 0
107+
}
104108

105109
override DataFlow::Node getEntryNode(DataFlow::CallNode c) {
106110
exists(DataFlow::PostUpdateNode pun, DataFlow::Node init |
@@ -181,7 +185,11 @@ private class OutResult extends FunctionOutput, TOutResult {
181185

182186
override predicate isResult() { index = -1 }
183187

184-
override predicate isResult(int i) { i = index and i >= 0 }
188+
override predicate isResult(int i) {
189+
i = 0 and isResult()
190+
or
191+
i = index and i >= 0
192+
}
185193

186194
override DataFlow::Node getEntryNode(FuncDef f) {
187195
// return expressions

ql/src/semmle/go/dataflow/internal/DataFlowPrivate.qll

Lines changed: 6 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@ private import DataFlowUtil
33
private import DataFlowImplCommon
44

55
private newtype TReturnKind =
6-
TSingleReturn() or
7-
TMultiReturn(int i) { exists(SignatureType st | exists(st.getResultType(i))) }
6+
MkReturnKind(int i) { exists(SignatureType st | exists(st.getResultType(i))) }
87

98
/**
109
* A return kind. A return kind describes how a value can be returned
@@ -13,23 +12,14 @@ private newtype TReturnKind =
1312
*/
1413
class ReturnKind extends TReturnKind {
1514
/** Gets a textual representation of this return kind. */
16-
string toString() {
17-
this = TSingleReturn() and
18-
result = "return"
19-
or
20-
exists(int i | this = TMultiReturn(i) | result = "return[" + i + "]")
21-
}
15+
string toString() { exists(int i | this = MkReturnKind(i) | result = "return[" + i + "]") }
2216
}
2317

2418
/** A data flow node that represents returning a value from a function. */
2519
class ReturnNode extends ResultNode {
2620
ReturnKind kind;
2721

28-
ReturnNode() {
29-
exists(int nr | nr = fd.getType().getNumResult() |
30-
if nr = 1 then kind = TSingleReturn() else kind = TMultiReturn(i)
31-
)
32-
}
22+
ReturnNode() { kind = MkReturnKind(i) }
3323

3424
/** Gets the kind of this returned value. */
3525
ReturnKind getKind() { result = kind }
@@ -40,12 +30,7 @@ class OutNode extends DataFlow::Node {
4030
DataFlow::CallNode call;
4131
int i;
4232

43-
OutNode() {
44-
this = call.getResult() and
45-
i = -1
46-
or
47-
this = call.getResult(i)
48-
}
33+
OutNode() { this = call.getResult(i) }
4934

5035
/** Gets the underlying call. */
5136
DataFlowCall getCall() { result = call.asExpr() }
@@ -56,11 +41,8 @@ class OutNode extends DataFlow::Node {
5641
* `kind`.
5742
*/
5843
OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) {
59-
exists(DataFlow::CallNode c | c.asExpr() = call |
60-
kind = TSingleReturn() and
61-
result = c.getResult()
62-
or
63-
exists(int i | kind = TMultiReturn(i) | result = c.getResult(i))
44+
exists(DataFlow::CallNode c, int i | c.asExpr() = call and kind = MkReturnKind(i) |
45+
result = c.getResult(i)
6446
)
6547
}
6648

ql/src/semmle/go/dataflow/internal/DataFlowUtil.qll

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -327,8 +327,15 @@ class CallNode extends ExprNode {
327327
/** Gets a function passed as the `i`th argument of this call. */
328328
FunctionNode getCallback(int i) { result.getASuccessor*() = this.getArgument(i) }
329329

330-
/** Gets the data-flow node corresponding to the `i`th result of this call. */
331-
Node getResult(int i) { result = extractTupleElement(this, i) }
330+
/**
331+
* Gets the data-flow node corresponding to the `i`th result of this call.
332+
*
333+
* If there is a single result then it is considered to be the 0th result. */
334+
Node getResult(int i) {
335+
i = 0 and result = getResult()
336+
or
337+
result = extractTupleElement(this, i)
338+
}
332339

333340
/**
334341
* Gets the data-flow node corresponding to the result of this call.
@@ -338,6 +345,9 @@ class CallNode extends ExprNode {
338345
*/
339346
Node getResult() { not getType() instanceof TupleType and result = this }
340347

348+
/** Gets a result of this call. */
349+
Node getAResult() { result = this.getResult(_) }
350+
341351
/** Gets the data flow node corresponding to the receiver of this call, if any. */
342352
Node getReceiver() { result = getACalleeSource().(MethodReadNode).getReceiver() }
343353
}

ql/src/semmle/go/frameworks/Stdlib.qll

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ module PathFilePath {
6262

6363
override predicate hasTaintFlow(DataFlow::FunctionInput inp, DataFlow::FunctionOutput outp) {
6464
inp.isParameter(_) and
65-
(outp.isResult() or outp.isResult(_))
65+
outp.isResult(_)
6666
}
6767
}
6868
}
@@ -472,7 +472,7 @@ module Path {
472472

473473
override predicate hasTaintFlow(DataFlow::FunctionInput inp, DataFlow::FunctionOutput outp) {
474474
inp.isParameter(_) and
475-
(outp.isResult() or outp.isResult(_))
475+
outp.isResult(_)
476476
}
477477
}
478478
}
@@ -684,8 +684,7 @@ module URL {
684684
}
685685

686686
override predicate hasTaintFlow(DataFlow::FunctionInput inp, DataFlow::FunctionOutput outp) {
687-
inp.isReceiver() and
688-
if getName() = "Password" then outp.isResult(0) else outp.isResult()
687+
inp.isReceiver() and outp.isResult(0)
689688
}
690689
}
691690

ql/src/semmle/go/security/ReflectedXssCustomizations.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ module ReflectedXss {
7575
pred.getStringValue().regexpMatch("^[^<].*")
7676
or
7777
// json data cannot begin with `<`
78-
pred = any(EncodingJson::MarshalFunction mf).getOutput().getExitNode(_)
78+
exists(EncodingJson::MarshalFunction mf | pred = mf.getOutput().getNode(mf.getACall()))
7979
)
8080
)
8181
}

ql/test/library-tests/semmle/go/dataflow/FunctionInputsAndOutputs/FunctionInput_getEntryNode.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,4 @@
1616
| receiver | reset.go:12:2:12:21 | call to Reset | reset.go:12:2:12:7 | reader |
1717
| receiver | tst.go:10:2:10:29 | call to ReadFrom | tst.go:10:2:10:12 | bytesBuffer |
1818
| result | tst.go:9:17:9:33 | call to new | tst.go:9:2:9:12 | definition of bytesBuffer |
19+
| result 0 | tst.go:9:17:9:33 | call to new | tst.go:9:2:9:12 | definition of bytesBuffer |

ql/test/library-tests/semmle/go/dataflow/FunctionInputsAndOutputs/FunctionOutput_getExitNode.expected

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,11 @@
77
| result | main.go:53:2:53:22 | call to op2 | main.go:53:2:53:22 | call to op2 |
88
| result | main.go:53:14:53:21 | call to bump | main.go:53:14:53:21 | call to bump |
99
| result | tst.go:9:17:9:33 | call to new | tst.go:9:17:9:33 | call to new |
10+
| result 0 | main.go:51:2:51:14 | call to op | main.go:51:2:51:14 | call to op |
11+
| result 0 | main.go:53:2:53:22 | call to op2 | main.go:53:2:53:22 | call to op2 |
12+
| result 0 | main.go:53:14:53:21 | call to bump | main.go:53:14:53:21 | call to bump |
1013
| result 0 | main.go:54:10:54:15 | call to test | main.go:54:2:54:15 | ... := ...[0] |
1114
| result 0 | main.go:56:9:56:15 | call to test2 | main.go:56:2:56:15 | ... = ...[0] |
15+
| result 0 | tst.go:9:17:9:33 | call to new | tst.go:9:17:9:33 | call to new |
1216
| result 1 | main.go:54:10:54:15 | call to test | main.go:54:2:54:15 | ... := ...[1] |
1317
| result 1 | main.go:56:9:56:15 | call to test2 | main.go:56:2:56:15 | ... = ...[1] |
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
| main.go:51:2:51:14 | call to op | main.go:51:2:51:14 | call to op | result |
2+
| main.go:53:2:53:22 | call to op2 | main.go:53:2:53:22 | call to op2 | result |
3+
| main.go:53:14:53:21 | call to bump | main.go:53:14:53:21 | call to bump | result |
4+
| tst.go:9:17:9:33 | call to new | tst.go:9:17:9:33 | call to new | result |
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import go
2+
3+
from FunctionOutput outp, DataFlow::CallNode c, DataFlow::Node nodeTo
4+
where outp.isResult() and nodeTo = outp.getNode(c)
5+
select c, nodeTo, outp

0 commit comments

Comments
 (0)