Skip to content

Commit d0f4c2f

Browse files
committed
C++: product flow prototype
1 parent 9e0c82e commit d0f4c2f

File tree

1 file changed

+111
-0
lines changed

1 file changed

+111
-0
lines changed
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
import semmle.code.cpp.ir.dataflow.DataFlow
2+
import semmle.code.cpp.ir.dataflow.DataFlow2
3+
4+
module ProductFlow {
5+
abstract class Configuration extends string {
6+
bindingset[this]
7+
Configuration() { any() }
8+
9+
/**
10+
* Holds if `(source1, source2)` is a relevant data flow source.
11+
*
12+
* `source1` and `source2` must belong to the same callable.
13+
*/
14+
abstract predicate isSourcePair(DataFlow::Node source1, DataFlow::Node source2);
15+
16+
/**
17+
* Holds if `(sink1, sink2)` is a relevant data flow sink.
18+
*
19+
* `sink1` and `sink2` must belong to the same callable.
20+
*/
21+
abstract predicate isSinkPair(DataFlow::Node sink1, DataFlow::Node sink2);
22+
23+
predicate hasFlowPath(
24+
DataFlow::PathNode source1, DataFlow2::PathNode source2, DataFlow::PathNode sink1,
25+
DataFlow2::PathNode sink2
26+
) {
27+
isSourcePair(source1.getNode(), source2.getNode()) and
28+
isSinkPair(sink1.getNode(), sink2.getNode()) and
29+
reachablePair(this, source1, source2, sink1, sink2)
30+
}
31+
}
32+
33+
class Conf1 extends DataFlow::Configuration {
34+
Conf1() { this = "Conf1" }
35+
36+
override predicate isSource(DataFlow::Node source) {
37+
exists(Configuration conf | conf.isSourcePair(source, _))
38+
}
39+
40+
override predicate isSink(DataFlow::Node sink) {
41+
exists(Configuration conf | conf.isSinkPair(sink, _))
42+
}
43+
}
44+
45+
class Conf2 extends DataFlow2::Configuration {
46+
Conf2() { this = "Conf2" }
47+
48+
override predicate isSource(DataFlow::Node source) {
49+
exists(Configuration conf | conf.isSourcePair(_, source))
50+
}
51+
52+
override predicate isSink(DataFlow::Node sink) {
53+
exists(Configuration conf | conf.isSinkPair(_, sink))
54+
}
55+
}
56+
57+
predicate reachablePair1(
58+
Configuration conf, DataFlow::PathNode source1, DataFlow2::PathNode source2,
59+
DataFlow::PathNode node1, DataFlow2::PathNode node2
60+
) {
61+
reachablePair(conf, source1, source2, node1, node2)
62+
or
63+
exists(DataFlow::PathNode mid1 |
64+
reachablePair1(conf, source1, source2, mid1, node2) and
65+
mid1.getASuccessor() = node1 and
66+
mid1.getNode().getFunction() = node1.getNode().getFunction()
67+
)
68+
}
69+
70+
predicate reachablePair2(
71+
Configuration conf, DataFlow::PathNode source1, DataFlow2::PathNode source2,
72+
DataFlow::PathNode node1, DataFlow2::PathNode node2
73+
) {
74+
reachablePair1(conf, source1, source2, node1, node2) // TODO: restrict more
75+
or
76+
exists(DataFlow2::PathNode mid2 |
77+
reachablePair2(conf, source1, source2, node1, mid2) and
78+
mid2.getASuccessor() = node2 and
79+
mid2.getNode().getFunction() = node2.getNode().getFunction()
80+
)
81+
}
82+
83+
predicate interprocStep(
84+
Configuration conf, DataFlow::PathNode source1, DataFlow2::PathNode source2,
85+
DataFlow::PathNode node1, DataFlow2::PathNode node2
86+
) {
87+
exists(DataFlow::PathNode mid1, DataFlow2::PathNode mid2, Function funcMid, Function func |
88+
reachablePair2(conf, source1, source2, mid1, mid2) and
89+
mid1.getASuccessor() = node1 and
90+
mid2.getASuccessor() = node2 and
91+
mid1.getNode().getFunction() = funcMid and // TODO: recursive function weirdness?
92+
mid2.getNode().getFunction() = funcMid and
93+
node1.getNode().getFunction() = func and
94+
node2.getNode().getFunction() = func and
95+
funcMid != func
96+
)
97+
}
98+
99+
predicate reachablePair(
100+
Configuration conf, DataFlow::PathNode source1, DataFlow2::PathNode source2,
101+
DataFlow::PathNode node1, DataFlow2::PathNode node2
102+
) {
103+
conf.isSourcePair(node1.getNode(), node2.getNode()) and
104+
node1.isSource() and
105+
node2.isSource() and
106+
source1 = node1 and
107+
source2 = node2
108+
or
109+
interprocStep(conf, source1, source2, node1, node2)
110+
}
111+
}

0 commit comments

Comments
 (0)