Skip to content

Commit 6c35f7c

Browse files
committed
feat(dataflow): Add initial DF libs
1 parent 8d1687f commit 6c35f7c

File tree

6 files changed

+776
-0
lines changed

6 files changed

+776
-0
lines changed
Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
private import bicep as Bicep
2+
private import codeql.Locations
3+
private import codeql.bicep.CFG
4+
private import DataFlowPrivate
5+
private import codeql.util.Boolean
6+
private import codeql.util.Unit
7+
8+
newtype TReturnKind = TNormalReturnKind()
9+
10+
/**
11+
* Gets a node that can read the value returned from `call` with return kind
12+
* `kind`.
13+
*/
14+
OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) { call = result.getCall(kind) }
15+
16+
/**
17+
* A return kind. A return kind describes how a value can be returned
18+
* from a callable.
19+
*/
20+
abstract class ReturnKind extends TReturnKind {
21+
/** Gets a textual representation of this position. */
22+
abstract string toString();
23+
}
24+
25+
/**
26+
* A value returned from a callable using a `return` statement or an expression
27+
* body, that is, a "normal" return.
28+
*/
29+
class NormalReturnKind extends ReturnKind, TNormalReturnKind {
30+
override string toString() { result = "return" }
31+
}
32+
33+
/** A callable defined in library code, identified by a unique string. */
34+
abstract class LibraryCallable extends string {
35+
bindingset[this]
36+
LibraryCallable() { any() }
37+
38+
/** Gets a call to this library callable. */
39+
Bicep::UserDefinedFunction getACall() { none() }
40+
}
41+
42+
/**
43+
* A callable. This includes callables from source code, as well as callables
44+
* defined in library code.
45+
*/
46+
class DataFlowCallable extends TDataFlowCallable {
47+
/**
48+
* Gets the underlying CFG scope, if any.
49+
*
50+
* This is usually a `Callable`, but can also be a `Toplevel` file.
51+
*/
52+
CfgScope asCfgScope() { this = TCfgScope(result) }
53+
54+
/** Gets the underlying library callable, if any. */
55+
LibraryCallable asLibraryCallable() { this = TLibraryCallable(result) }
56+
57+
/** Gets a textual representation of this callable. */
58+
string toString() { result = [this.asCfgScope().toString(), this.asLibraryCallable()] }
59+
60+
/** Gets the location of this callable. */
61+
Location getLocation() {
62+
result = this.asCfgScope().getLocation()
63+
or
64+
this instanceof TLibraryCallable
65+
}
66+
67+
/** Gets a best-effort total ordering. */
68+
int totalorder() { none() }
69+
}
70+
71+
/**
72+
* A call. This includes calls from source code, as well as call(back)s
73+
* inside library callables with a flow summary.
74+
*/
75+
abstract class DataFlowCall extends TDataFlowCall {
76+
/** Gets the enclosing callable. */
77+
abstract DataFlowCallable getEnclosingCallable();
78+
79+
/** Gets the underlying source code call, if any. */
80+
abstract CfgNodes::StmtNodes::CallCfgNode asCall();
81+
82+
/** Gets a textual representation of this call. */
83+
abstract string toString();
84+
85+
/** Gets the location of this call. */
86+
abstract Location getLocation();
87+
88+
DataFlowCallable getARuntimeTarget() { none() }
89+
90+
ArgumentNode getAnArgumentNode() { none() }
91+
92+
/** Gets a best-effort total ordering. */
93+
int totalorder() { none() }
94+
95+
/**
96+
* Holds if this element is at the specified location.
97+
* The location spans column `startcolumn` of line `startline` to
98+
* column `endcolumn` of line `endline` in file `filepath`.
99+
* For more information, see
100+
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries).
101+
*/
102+
predicate hasLocationInfo(
103+
string filepath, int startline, int startcolumn, int endline, int endcolumn
104+
) {
105+
this.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
106+
}
107+
}
108+
109+
class NormalCall extends DataFlowCall, TNormalCall {
110+
private CfgNodes::StmtNodes::CallCfgNode c;
111+
112+
NormalCall() { this = TNormalCall(c) }
113+
114+
override CfgNodes::StmtNodes::CallCfgNode asCall() { result = c }
115+
116+
override DataFlowCallable getEnclosingCallable() { result = TCfgScope(c.getScope()) }
117+
118+
override string toString() { result = c.toString() }
119+
120+
override Location getLocation() { result = c.getLocation() }
121+
}
122+
123+
/** A call for which we want to compute call targets. */
124+
private class RelevantCall extends CfgNodes::StmtNodes::CallCfgNode { }
125+
126+
/** Holds if `call` may resolve to the returned source-code method. */
127+
private DataFlowCallable viableSourceCallable(DataFlowCall call) {
128+
none() // TODO
129+
or
130+
result = any(AdditionalCallTarget t).viableTarget(call.asCall())
131+
}
132+
133+
/**
134+
* A unit class for adding additional call steps.
135+
*
136+
* Extend this class to add additional call steps to the data flow graph.
137+
*/
138+
class AdditionalCallTarget extends Unit {
139+
/**
140+
* Gets a viable target for `call`.
141+
*/
142+
abstract DataFlowCallable viableTarget(CfgNodes::StmtNodes::CallCfgNode call);
143+
}
144+
145+
/** Holds if `call` may resolve to the returned summarized library method. */
146+
DataFlowCallable viableLibraryCallable(DataFlowCall call) {
147+
exists(LibraryCallable callable |
148+
result = TLibraryCallable(callable) and
149+
call.asCall().getStmt() = callable.getACall()
150+
)
151+
}
152+
153+
cached
154+
private module Cached {
155+
cached
156+
newtype TDataFlowCallable =
157+
TCfgScope(CfgScope scope) or
158+
TLibraryCallable(LibraryCallable callable)
159+
160+
cached
161+
newtype TDataFlowCall = TNormalCall(CfgNodes::StmtNodes::CallCfgNode c)
162+
163+
/** Gets a viable run-time target for the call `call`. */
164+
cached
165+
DataFlowCallable viableCallable(DataFlowCall call) {
166+
result = viableSourceCallable(call)
167+
or
168+
result = viableLibraryCallable(call)
169+
}
170+
171+
cached
172+
newtype TArgumentPosition =
173+
TPositionalArgumentPosition(int pos) { exists(Bicep::CallExpression c | exists(c.getArgument(pos))) }
174+
175+
cached
176+
newtype TParameterPosition = TPositionalParameterPosition(int pos) { none() /* TODO */ }
177+
}
178+
179+
import Cached
180+
181+
/** A parameter position. */
182+
class ParameterPosition extends TParameterPosition {
183+
/** Holds if this position represents a positional parameter at position `pos`. */
184+
predicate isPositional(int pos) { this = TPositionalParameterPosition(pos) }
185+
186+
/** Gets a textual representation of this position. */
187+
string toString() { exists(int pos | this.isPositional(pos) and result = "position " + pos) }
188+
}
189+
190+
/** An argument position. */
191+
class ArgumentPosition extends TArgumentPosition {
192+
/** Holds if this position represents a positional argument at position `pos`. */
193+
predicate isPositional(int pos) { this = TPositionalArgumentPosition(pos) }
194+
195+
/** Gets a textual representation of this position. */
196+
string toString() { exists(int pos | this.isPositional(pos) and result = "position " + pos) }
197+
}
198+
199+
/** Holds if arguments at position `apos` match parameters at position `ppos`. */
200+
pragma[nomagic]
201+
predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) {
202+
exists(int pos | ppos.isPositional(pos) and apos.isPositional(pos))
203+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
private import DataFlowImplCommon
2+
private import DataFlowImplSpecific::Private
3+
import DataFlowImplSpecific::Public
4+
import DataFlowImplCommonPublic
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
private import bicep
2+
private import DataFlowImplSpecific
3+
private import codeql.dataflow.internal.DataFlowImplCommon
4+
import MakeImplCommon<Location, BicepDataFlow>
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/**
2+
* Provides bicep-specific definitions for use in the data flow library.
3+
*/
4+
5+
private import bicep
6+
private import codeql.dataflow.DataFlow
7+
8+
module Private {
9+
import DataFlowPrivate
10+
import DataFlowDispatch
11+
}
12+
13+
module Public {
14+
import DataFlowPublic
15+
}
16+
17+
module BicepDataFlow implements InputSig<Location> {
18+
import Private
19+
import Public
20+
21+
class ParameterNode = Private::ParameterNodeImpl;
22+
23+
Node exprNode(DataFlowExpr e) { result = Public::exprNode(e) }
24+
25+
// predicate neverSkipInPathGraph = Private::neverSkipInPathGraph/1;
26+
}

0 commit comments

Comments
 (0)