Skip to content

Commit 1d12159

Browse files
authored
Merge pull request #323 from github/hvitved/get-value-text
Introduce `Expr::getValueText`
2 parents 0fcb079 + 0822518 commit 1d12159

File tree

6 files changed

+639
-3
lines changed

6 files changed

+639
-3
lines changed

ql/lib/codeql/ruby/ast/Constant.qll

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,8 @@ class ConstantReadAccess extends ConstantAccess {
139139
result = lookupConst(resolveScopeExpr(this.getScopeExpr()), this.getName())
140140
}
141141

142+
override string getValueText() { result = this.getValue().getValueText() }
143+
142144
final override string getAPrimaryQlClass() { result = "ConstantReadAccess" }
143145
}
144146

ql/lib/codeql/ruby/ast/Expr.qll

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
private import codeql.ruby.AST
2+
private import codeql.ruby.CFG
23
private import internal.AST
34
private import internal.TreeSitter
45

@@ -7,7 +8,12 @@ private import internal.TreeSitter
78
*
89
* This is the root QL class for all expressions.
910
*/
10-
class Expr extends Stmt, TExpr { }
11+
class Expr extends Stmt, TExpr {
12+
/** Gets the textual (constant) value of this expression, if any. */
13+
string getValueText() {
14+
forex(CfgNodes::ExprCfgNode n | n = this.getAControlFlowNode() | result = n.getValueText())
15+
}
16+
}
1117

1218
/**
1319
* A reference to the current object. For example:

ql/lib/codeql/ruby/ast/Literal.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ class Literal extends Expr, TLiteral {
1616
* For complex literals, such as arrays, hashes, and strings with
1717
* interpolations, this predicate has no result.
1818
*/
19-
string getValueText() { none() }
19+
override string getValueText() { none() }
2020
}
2121

2222
/**

ql/lib/codeql/ruby/controlflow/CfgNodes.qll

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
private import codeql.ruby.AST
44
private import codeql.ruby.controlflow.BasicBlocks
5+
private import codeql.ruby.dataflow.SSA
56
private import ControlFlowGraph
67
private import internal.ControlFlowGraphImpl
78
private import internal.Splitting
@@ -98,6 +99,16 @@ class ExprCfgNode extends AstCfgNode {
9899

99100
/** Gets the underlying expression. */
100101
Expr getExpr() { result = e }
102+
103+
private ExprCfgNode getSource() {
104+
exists(Ssa::WriteDefinition def |
105+
def.assigns(result) and
106+
this = def.getARead()
107+
)
108+
}
109+
110+
/** Gets the textual (constant) value of this expression, if any. */
111+
string getValueText() { result = this.getSource().getValueText() }
101112
}
102113

103114
/** A control-flow node that wraps a return-like statement. */
@@ -164,7 +175,19 @@ abstract private class ExprChildMapping extends Expr {
164175

165176
/** Provides classes for control-flow nodes that wrap AST expressions. */
166177
module ExprNodes {
167-
// TODO: Add more classes
178+
private class LiteralChildMapping extends ExprChildMapping, Literal {
179+
override predicate relevantChild(Expr e) { none() }
180+
}
181+
182+
/** A control-flow node that wraps an `ArrayLiteral` AST expression. */
183+
class LiteralCfgNode extends ExprCfgNode {
184+
override LiteralChildMapping e;
185+
186+
override Literal getExpr() { result = super.getExpr() }
187+
188+
override string getValueText() { result = e.getValueText() }
189+
}
190+
168191
private class AssignExprChildMapping extends ExprChildMapping, AssignExpr {
169192
override predicate relevantChild(Expr e) { e = this.getAnOperand() }
170193
}
@@ -209,6 +232,49 @@ module ExprNodes {
209232

210233
/** Gets the right operand of this binary operation. */
211234
final ExprCfgNode getRightOperand() { e.hasCfgChild(bo.getRightOperand(), this, result) }
235+
236+
final override string getValueText() {
237+
exists(string left, string right, string op |
238+
left = this.getLeftOperand().getValueText() and
239+
right = this.getRightOperand().getValueText() and
240+
op = this.getExpr().getOperator()
241+
|
242+
op = "+" and
243+
(
244+
result = (left.toInt() + right.toInt()).toString()
245+
or
246+
not (exists(left.toInt()) and exists(right.toInt())) and
247+
result = (left.toFloat() + right.toFloat()).toString()
248+
or
249+
not (exists(left.toFloat()) and exists(right.toFloat())) and
250+
result = left + right
251+
)
252+
or
253+
op = "-" and
254+
(
255+
result = (left.toInt() - right.toInt()).toString()
256+
or
257+
not (exists(left.toInt()) and exists(right.toInt())) and
258+
result = (left.toFloat() - right.toFloat()).toString()
259+
)
260+
or
261+
op = "*" and
262+
(
263+
result = (left.toInt() * right.toInt()).toString()
264+
or
265+
not (exists(left.toInt()) and exists(right.toInt())) and
266+
result = (left.toFloat() * right.toFloat()).toString()
267+
)
268+
or
269+
op = "/" and
270+
(
271+
result = (left.toInt() / right.toInt()).toString()
272+
or
273+
not (exists(left.toInt()) and exists(right.toInt())) and
274+
result = (left.toFloat() / right.toFloat()).toString()
275+
)
276+
)
277+
}
212278
}
213279

214280
private class BlockArgumentChildMapping extends ExprChildMapping, BlockArgument {

0 commit comments

Comments
 (0)