Skip to content

Commit 077bae5

Browse files
committed
Go: don't use WriteNode for channel writes
I overlooked the fact that this has a WriteInstruction, which wasn't bound in the channel-write case, but somehow the evaluator discarded the implied cartesian product until last night's performance evaluation. Rather than try to cram channel writes into WriteInstruction, just handle them as their own beast.
1 parent 1eb0f6a commit 077bae5

File tree

6 files changed

+74
-13
lines changed

6 files changed

+74
-13
lines changed

go/ql/lib/semmle/go/controlflow/ControlFlowGraph.qll

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -166,21 +166,11 @@ module ControlFlow {
166166
)
167167
}
168168

169-
/**
170-
* Holds if this node writes `rhs` to `channel`.
171-
*/
172-
predicate writesToChannel(DataFlow::ExprNode channel, DataFlow::ExprNode rhs) {
173-
exists(SendStmt send |
174-
send.getChannel() = channel.asExpr() and
175-
send.getValue() = rhs.asExpr()
176-
)
177-
}
178-
179169
/**
180170
* Holds if this node sets any field or element of `base` to `rhs`.
181171
*/
182172
predicate writesComponent(DataFlow::Node base, DataFlow::Node rhs) {
183-
writesElement(base, _, rhs) or writesField(base, _, rhs) or writesToChannel(base, rhs)
173+
writesElement(base, _, rhs) or writesField(base, _, rhs)
184174
}
185175
}
186176

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ predicate containerStoreStep(Node node1, Node node2, Content c) {
2424
)
2525
or
2626
c instanceof CollectionContent and
27-
exists(Write w | w.writesToChannel(node2, node1))
27+
exists(SendStmt send |
28+
send.getChannel() = node2.(ExprNode).asExpr() and send.getValue() = node1.(ExprNode).asExpr()
29+
)
2830
or
2931
c instanceof MapKeyContent and
3032
node2.getType() instanceof MapType and

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -634,7 +634,10 @@ module Public {
634634
predicate isReceiverOf(MethodDecl m) { parm.isReceiverOf(m) }
635635
}
636636

637-
private Node getADirectlyWrittenNode() { exists(Write w | w.writesComponent(result, _)) }
637+
private Node getADirectlyWrittenNode() {
638+
exists(Write w | w.writesComponent(result, _)) or
639+
result = DataFlow::exprNode(any(SendStmt s).getChannel())
640+
}
638641

639642
private DataFlow::Node getAccessPathPredecessor(DataFlow::Node node) {
640643
result = node.(PointerDereferenceNode).getOperand()
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
edges
2+
| test.go:9:10:9:12 | selection of c [collection] : string | test.go:9:8:9:12 | <-... |
3+
| test.go:13:16:13:16 | definition of s [pointer, c, collection] : string | test.go:16:3:16:3 | s [pointer, c, collection] : string |
4+
| test.go:15:11:15:18 | call to source : string | test.go:16:10:16:13 | data : string |
5+
| test.go:16:3:16:3 | implicit dereference [c, collection] : string | test.go:13:16:13:16 | definition of s [pointer, c, collection] : string |
6+
| test.go:16:3:16:3 | implicit dereference [c, collection] : string | test.go:16:3:16:5 | selection of c [collection] : string |
7+
| test.go:16:3:16:3 | s [pointer, c, collection] : string | test.go:16:3:16:3 | implicit dereference [c, collection] : string |
8+
| test.go:16:3:16:5 | selection of c [collection] : string | test.go:9:10:9:12 | selection of c [collection] : string |
9+
| test.go:16:3:16:5 | selection of c [collection] : string | test.go:16:3:16:3 | implicit dereference [c, collection] : string |
10+
| test.go:16:10:16:13 | data : string | test.go:16:3:16:5 | selection of c [collection] : string |
11+
nodes
12+
| test.go:9:8:9:12 | <-... | semmle.label | <-... |
13+
| test.go:9:10:9:12 | selection of c [collection] : string | semmle.label | selection of c [collection] : string |
14+
| test.go:13:16:13:16 | definition of s [pointer, c, collection] : string | semmle.label | definition of s [pointer, c, collection] : string |
15+
| test.go:15:11:15:18 | call to source : string | semmle.label | call to source : string |
16+
| test.go:16:3:16:3 | implicit dereference [c, collection] : string | semmle.label | implicit dereference [c, collection] : string |
17+
| test.go:16:3:16:3 | s [pointer, c, collection] : string | semmle.label | s [pointer, c, collection] : string |
18+
| test.go:16:3:16:5 | selection of c [collection] : string | semmle.label | selection of c [collection] : string |
19+
| test.go:16:10:16:13 | data : string | semmle.label | data : string |
20+
subpaths
21+
#select
22+
| test.go:15:11:15:18 | call to source : string | test.go:15:11:15:18 | call to source : string | test.go:9:8:9:12 | <-... | path |
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package test
2+
3+
type State struct {
4+
c chan string
5+
}
6+
7+
func handler(s *State) {
8+
9+
sink(<-s.c)
10+
11+
}
12+
13+
func requester(s *State) {
14+
15+
data := source()
16+
s.c <- data
17+
18+
}
19+
20+
func source() string {
21+
22+
return "tainted"
23+
24+
}
25+
26+
func sink(s string) { }
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import go
2+
import DataFlow::PathGraph
3+
4+
class TestConfig extends DataFlow::Configuration {
5+
TestConfig() { this = "test config" }
6+
7+
override predicate isSource(DataFlow::Node source) {
8+
source.(DataFlow::CallNode).getTarget().getName() = "source"
9+
}
10+
11+
override predicate isSink(DataFlow::Node sink) {
12+
sink = any(DataFlow::CallNode c | c.getTarget().getName() = "sink").getAnArgument()
13+
}
14+
}
15+
16+
from DataFlow::PathNode source, DataFlow::PathNode sink, TestConfig c
17+
where c.hasFlowPath(source, sink)
18+
select source, source, sink, "path"

0 commit comments

Comments
 (0)