Skip to content

Commit 3c0f822

Browse files
authored
Merge pull request #111 from github/hvitved/dataflow
Initial data flow library
2 parents 2770b4f + de77a7f commit 3c0f822

File tree

9 files changed

+5592
-0
lines changed

9 files changed

+5592
-0
lines changed

ql/src/codeql_ruby/DataFlow.qll

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/**
2+
* Provides classes for performing local (intra-procedural) and
3+
* global (inter-procedural) data flow analyses.
4+
*/
5+
module DataFlow {
6+
import codeql_ruby.dataflow.internal.DataFlowImpl
7+
}

ql/src/codeql_ruby/controlflow/CfgNodes.qll

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,23 @@ abstract private class ExprChildMapping extends Expr {
176176
/** Provides classes for control-flow nodes that wrap AST expressions. */
177177
module ExprNodes {
178178
// TODO: Add more classes
179+
private class AssignmentExprChildMapping extends ExprChildMapping, Assignment {
180+
override predicate relevantChild(Expr e) { e = this.getAnOperand() }
181+
}
182+
183+
/** A control-flow node that wraps an `Assignment` AST expression. */
184+
class AssignmentCfgNode extends ExprCfgNode {
185+
override AssignmentExprChildMapping e;
186+
187+
final override Assignment getExpr() { result = ExprCfgNode.super.getExpr() }
188+
189+
/** Gets the LHS of this assignment. */
190+
final ExprCfgNode getLhs() { e.hasCfgChild(e.getLhs(), this, result) }
191+
192+
/** Gets the RHS of this assignment. */
193+
final ExprCfgNode getRhs() { e.hasCfgChild(e.getRhs(), this, result) }
194+
}
195+
179196
private class BinaryOperationExprChildMapping extends ExprChildMapping, BinaryOperation {
180197
override predicate relevantChild(Expr e) { e = this.getAnOperand() }
181198
}
@@ -193,6 +210,40 @@ module ExprNodes {
193210
final ExprCfgNode getRightOperand() { e.hasCfgChild(e.getRightOperand(), this, result) }
194211
}
195212

213+
private class CallExprChildMapping extends ExprChildMapping, Call {
214+
override predicate relevantChild(Expr e) { e = [this.getAnArgument(), this.getReceiver()] }
215+
}
216+
217+
/** A control-flow node that wraps a `Call` AST expression. */
218+
class CallCfgNode extends ExprCfgNode {
219+
override CallExprChildMapping e;
220+
221+
final override Call getExpr() { result = ExprCfgNode.super.getExpr() }
222+
223+
/** Gets the `n`th argument of this call. */
224+
final ExprCfgNode getArgument(int n) { e.hasCfgChild(e.getArgument(n), this, result) }
225+
226+
/** Gets the receiver of this call. */
227+
final ExprCfgNode getReceiver() { e.hasCfgChild(e.getReceiver(), this, result) }
228+
}
229+
230+
private class ExprSequenceChildMapping extends ExprChildMapping, ExprSequence {
231+
override predicate relevantChild(Expr e) { e = this.getAnExpr() }
232+
}
233+
234+
/** A control-flow node that wraps an `ExprSequence` AST expression. */
235+
class ExprSequenceCfgNode extends ExprCfgNode {
236+
override ExprSequenceChildMapping e;
237+
238+
final override ExprSequence getExpr() { result = ExprCfgNode.super.getExpr() }
239+
240+
/** Gets the last expression in this sequence, if any. */
241+
final ExprCfgNode getLastExpr() { e.hasCfgChild(e.getLastExpr(), this, result) }
242+
243+
/** Gets the 'n'th expression of this expression sequence. */
244+
final ExprCfgNode getExpr(int n) { e.hasCfgChild(e.getExpr(n), this, result) }
245+
}
246+
196247
/** A control-flow node that wraps a `VariableReadAccess` AST expression. */
197248
class VariableReadAccessCfgNode extends ExprCfgNode {
198249
override VariableReadAccess e;
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
private import ruby
2+
private import codeql_ruby.CFG
3+
private import DataFlowPrivate
4+
5+
newtype TReturnKind = TNormalReturnKind()
6+
7+
/**
8+
* Gets a node that can read the value returned from `call` with return kind
9+
* `kind`.
10+
*/
11+
OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) { call = result.getCall(kind) }
12+
13+
/**
14+
* A return kind. A return kind describes how a value can be returned
15+
* from a callable.
16+
*/
17+
abstract class ReturnKind extends TReturnKind {
18+
/** Gets a textual representation of this position. */
19+
abstract string toString();
20+
}
21+
22+
/**
23+
* A value returned from a callable using a `return` statement or an expression
24+
* body, that is, a "normal" return.
25+
*/
26+
class NormalReturnKind extends ReturnKind, TNormalReturnKind {
27+
override string toString() { result = "return" }
28+
}
29+
30+
class DataFlowCallable = CfgScope;
31+
32+
class DataFlowCall extends CfgNodes::ExprNodes::CallCfgNode {
33+
DataFlowCallable getEnclosingCallable() { result = this.getScope() }
34+
}
35+
36+
/** Gets a viable run-time target for the call `call`. */
37+
DataFlowCallable viableCallable(DataFlowCall call) { none() }
38+
39+
/**
40+
* Holds if the set of viable implementations that can be called by `call`
41+
* might be improved by knowing the call context. This is the case if the
42+
* call is a delegate call, or if the qualifier accesses a parameter of
43+
* the enclosing callable `c` (including the implicit `this` parameter).
44+
*/
45+
predicate mayBenefitFromCallContext(DataFlowCall call, Callable c) { none() }
46+
47+
/**
48+
* Gets a viable dispatch target of `call` in the context `ctx`. This is
49+
* restricted to those `call`s for which a context might make a difference.
50+
*/
51+
DataFlowCallable viableImplInCallContext(DataFlowCall call, DataFlowCall ctx) { none() }

0 commit comments

Comments
 (0)