Skip to content

Commit 198a594

Browse files
authored
Merge pull request #149 from microsoft/interprocedural-controlflow
C++: Add an interprocedural control-flow library
2 parents 60ca496 + bac9c7d commit 198a594

File tree

6 files changed

+826
-0
lines changed

6 files changed

+826
-0
lines changed
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import cpp
2+
3+
/**
4+
* Provides classes for performing global (inter-procedural) control flow analyses.
5+
*/
6+
module ControlFlow {
7+
private import internal.ControlFlowSpecific
8+
private import shared.ControlFlow
9+
import ControlFlowMake<Location, CppControlFlow>
10+
import Public
11+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
private import semmle.code.cpp.ir.IR
2+
private import cpp as Cpp
3+
private import ControlFlowPublic
4+
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate as DataFlowPrivate
5+
private import semmle.code.cpp.ir.dataflow.internal.DataFlowImplCommon as DataFlowImplCommon
6+
7+
predicate edge(Node n1, Node n2) { n1.asInstruction().getASuccessor() = n2.asInstruction() }
8+
9+
predicate callTarget(CallNode call, Callable target) {
10+
exists(DataFlowPrivate::DataFlowCall dfCall | dfCall.asCallInstruction() = call.asInstruction() |
11+
DataFlowImplCommon::viableCallableCached(dfCall).asSourceCallable() = target
12+
or
13+
DataFlowImplCommon::viableCallableLambda(dfCall, _).asSourceCallable() = target
14+
)
15+
}
16+
17+
predicate flowEntry(Callable c, Node entry) {
18+
entry.asInstruction().(EnterFunctionInstruction).getEnclosingFunction() = c
19+
}
20+
21+
predicate flowExit(Callable c, Node exitNode) {
22+
exitNode.asInstruction().(ExitFunctionInstruction).getEnclosingFunction() = c
23+
}
24+
25+
Callable getEnclosingCallable(Node n) { n.getEnclosingFunction() = result }
26+
27+
predicate hiddenNode(Node n) { n.asInstruction() instanceof PhiInstruction }
28+
29+
private newtype TSplit = TNone() { none() }
30+
31+
class Split extends TSplit {
32+
abstract string toString();
33+
34+
abstract Cpp::Location getLocation();
35+
36+
abstract predicate entry(Node n1, Node n2);
37+
38+
abstract predicate exit(Node n1, Node n2);
39+
40+
abstract predicate blocked(Node n1, Node n2);
41+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
private import semmle.code.cpp.ir.IR
2+
private import cpp
3+
4+
private newtype TNode = TInstructionNode(Instruction i)
5+
6+
abstract private class NodeImpl extends TNode {
7+
/** Gets the `Instruction` associated with this node, if any. */
8+
Instruction asInstruction() { result = this.(InstructionNode).getInstruction() }
9+
10+
/** Gets the `Expr` associated with this node, if any. */
11+
Expr asExpr() { result = this.(ExprNode).getExpr() }
12+
13+
/** Gets the `Parameter` associated with this node, if any. */
14+
Parameter asParameter() { result = this.(ParameterNode).getParameter() }
15+
16+
/** Gets the location of this node. */
17+
Location getLocation() { none() }
18+
19+
/**
20+
* Holds if this element is at the specified location.
21+
* The location spans column `startcolumn` of line `startline` to
22+
* column `endcolumn` of line `endline` in file `filepath`.
23+
* For more information, see
24+
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
25+
*/
26+
final predicate hasLocationInfo(
27+
string filepath, int startline, int startcolumn, int endline, int endcolumn
28+
) {
29+
this.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
30+
}
31+
32+
/** Gets a textual representation of this node. */
33+
abstract string toString();
34+
35+
/** Gets the enclosing callable of this node. */
36+
abstract Callable getEnclosingFunction();
37+
}
38+
39+
final class Node = NodeImpl;
40+
41+
private class InstructionNode extends NodeImpl {
42+
Instruction instr;
43+
44+
InstructionNode() { this = TInstructionNode(instr) }
45+
46+
/** Gets the `Instruction` associated with this node. */
47+
Instruction getInstruction() { result = instr }
48+
49+
final override Location getLocation() { result = instr.getLocation() }
50+
51+
final override string toString() { result = instr.getAst().toString() }
52+
53+
final override Callable getEnclosingFunction() { result = instr.getEnclosingFunction() }
54+
}
55+
56+
private class ExprNode extends InstructionNode {
57+
Expr e;
58+
59+
ExprNode() { e = this.getInstruction().getConvertedResultExpression() }
60+
61+
/** Gets the `Expr` associated with this node. */
62+
Expr getExpr() { result = e }
63+
}
64+
65+
private class ParameterNode extends InstructionNode {
66+
override InitializeParameterInstruction instr;
67+
Parameter p;
68+
69+
ParameterNode() { p = instr.getParameter() }
70+
71+
/** Gets the `Parameter` associated with this node. */
72+
Parameter getParameter() { result = p }
73+
}
74+
75+
class CallNode extends InstructionNode {
76+
override CallInstruction instr;
77+
}
78+
79+
class Callable = Function;
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/**
2+
* Provides IR-specific definitions for use in the data flow library.
3+
*/
4+
5+
private import cpp
6+
private import semmle.code.cpp.interproccontrolflow.shared.ControlFlow
7+
8+
module Private {
9+
import ControlFlowPrivate
10+
}
11+
12+
module Public {
13+
import ControlFlowPublic
14+
}
15+
16+
module CppControlFlow implements InputSig<Location> {
17+
import Private
18+
import Public
19+
}
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
private import codeql.util.Location
2+
3+
/** Provides language-specific control flow parameters. */
4+
signature module InputSig<LocationSig Location> {
5+
/**
6+
* A node in the control flow graph.
7+
*/
8+
class Node {
9+
/** Gets a textual representation of this element. */
10+
string toString();
11+
12+
/** Gets the location of this node. */
13+
Location getLocation();
14+
}
15+
16+
class CallNode extends Node;
17+
18+
class Callable;
19+
20+
predicate edge(Node n1, Node n2);
21+
22+
predicate callTarget(CallNode call, Callable target);
23+
24+
predicate flowEntry(Callable c, Node entry);
25+
26+
predicate flowExit(Callable c, Node exitNode);
27+
28+
Callable getEnclosingCallable(Node n);
29+
30+
predicate hiddenNode(Node n);
31+
32+
class Split {
33+
string toString();
34+
35+
Location getLocation();
36+
37+
predicate entry(Node n1, Node n2);
38+
39+
predicate exit(Node n1, Node n2);
40+
41+
predicate blocked(Node n1, Node n2);
42+
}
43+
}
44+
45+
private module Configs<LocationSig Location, InputSig<Location> Lang> {
46+
private import Lang
47+
48+
/** An input configuration for control flow. */
49+
signature module ConfigSig {
50+
/** Holds if `source` is a relevant control flow source. */
51+
predicate isSource(Node src);
52+
53+
/** Holds if `sink` is a relevant control flow sink. */
54+
predicate isSink(Node sink);
55+
56+
/** Holds if control flow should not proceed along the edge `n1 -> n2`. */
57+
default predicate isBarrierEdge(Node n1, Node n2) { none() }
58+
59+
/**
60+
* Holds if control flow through `node` is prohibited. This completely
61+
* removes `node` from the control flow graph.
62+
*/
63+
default predicate isBarrier(Node n) { none() }
64+
}
65+
66+
/** An input configuration for control flow using a label. */
67+
signature module LabelConfigSig {
68+
class Label;
69+
70+
/**
71+
* Holds if `source` is a relevant control flow source with the given
72+
* initial `l`.
73+
*/
74+
predicate isSource(Node src, Label l);
75+
76+
/**
77+
* Holds if `sink` is a relevant control flow sink accepting `l`.
78+
*/
79+
predicate isSink(Node sink, Label l);
80+
81+
/**
82+
* Holds if control flow should not proceed along the edge `n1 -> n2` when
83+
* the label is `l`.
84+
*/
85+
default predicate isBarrierEdge(Node n1, Node n2, Label l) { none() }
86+
87+
/**
88+
* Holds if control flow through `node` is prohibited when the label
89+
* is `l`.
90+
*/
91+
default predicate isBarrier(Node n, Label l) { none() }
92+
}
93+
}
94+
95+
module ControlFlowMake<LocationSig Location, InputSig<Location> Lang> {
96+
private import Lang
97+
private import internal.ControlFlowImpl::MakeImpl<Location, Lang>
98+
import Configs<Location, Lang>
99+
100+
/**
101+
* The output of a global control flow computation.
102+
*/
103+
signature module GlobalFlowSig {
104+
/**
105+
* A `Node` that is reachable from a source, and which can reach a sink.
106+
*/
107+
class PathNode;
108+
109+
/**
110+
* Holds if control can flow from `source` to `sink`.
111+
*
112+
* The corresponding paths are generated from the end-points and the graph
113+
* included in the module `PathGraph`.
114+
*/
115+
predicate flowPath(PathNode source, PathNode sink);
116+
}
117+
118+
/**
119+
* Constructs a global control flow computation.
120+
*/
121+
module Global<ConfigSig Config> implements GlobalFlowSig {
122+
private module C implements FullConfigSig {
123+
import DefaultLabel<Config>
124+
import Config
125+
}
126+
127+
import Impl<C>
128+
}
129+
130+
/**
131+
* Constructs a global control flow computation using a flow label.
132+
*/
133+
module GlobalWithLabel<LabelConfigSig Config> implements GlobalFlowSig {
134+
private module C implements FullConfigSig {
135+
import Config
136+
}
137+
138+
import Impl<C>
139+
}
140+
}

0 commit comments

Comments
 (0)