Skip to content

Commit 15bfeab

Browse files
committed
Ruby: Make getPreUpdateNode Unique Again
1 parent 68f6f9f commit 15bfeab

File tree

5 files changed

+62
-72
lines changed

5 files changed

+62
-72
lines changed

ruby/ql/consistency-queries/DataFlowConsistency.ql

+6-18
Original file line numberDiff line numberDiff line change
@@ -8,30 +8,18 @@ private import codeql.dataflow.internal.DataFlowImplConsistency
88
private module Input implements InputSig<Location, RubyDataFlow> {
99
private import RubyDataFlow
1010

11-
predicate postWithInFlowExclude(Node n) { n instanceof FlowSummaryNode }
11+
predicate postWithInFlowExclude(Node n) {
12+
n instanceof FlowSummaryNode
13+
or
14+
n.(PostUpdateNode).getPreUpdateNode().asExpr() = getPostUpdateReverseStep(_)
15+
}
1216

1317
predicate argHasPostUpdateExclude(ArgumentNode n) {
1418
n instanceof FlowSummaryNode
1519
or
1620
n instanceof SynthHashSplatArgumentNode
1721
or
18-
not isNonConstantExpr(getAPostUpdateNodeForArg(n.asExpr()))
19-
}
20-
21-
predicate postHasUniquePreExclude(PostUpdateNode n) {
22-
exists(CfgNodes::ExprCfgNode e, CfgNodes::ExprCfgNode arg |
23-
e = getAPostUpdateNodeForArg(arg) and
24-
e != arg and
25-
n = TExprPostUpdateNode(e)
26-
)
27-
}
28-
29-
predicate uniquePostUpdateExclude(Node n) {
30-
exists(CfgNodes::ExprCfgNode e, CfgNodes::ExprCfgNode arg |
31-
e = getAPostUpdateNodeForArg(arg) and
32-
e != arg and
33-
n.asExpr() = arg
34-
)
22+
not isNonConstantExpr(n.asExpr())
3523
}
3624

3725
predicate multipleArgumentCallExclude(ArgumentNode arg, DataFlowCall call) {

ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll

+23-17
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,22 @@ private CfgNodes::ExprCfgNode getALastEvalNode(CfgNodes::ExprCfgNode n) {
6666
)
6767
}
6868

69-
/** Gets a node for which to construct a post-update node for argument `arg`. */
70-
CfgNodes::ExprCfgNode getAPostUpdateNodeForArg(Argument arg) {
71-
result = getALastEvalNode*(arg) and
72-
not exists(getALastEvalNode(result))
69+
/**
70+
* Holds if a reverse local flow step should be added from the post-update node
71+
* for `e` to the post-update node for the result.
72+
*
73+
* This is needed to allow for side-effects on compound expressions to propagate
74+
* to sub components. For example, in
75+
*
76+
* ```ruby
77+
* (foo1; foo2).set_field(taint)
78+
* ```
79+
*
80+
* we add a reverse flow step from `[post] (foo1; foo2)` to `[post] foo2`,
81+
* in order for the side-effect of `set_field` to reach `foo2`.
82+
*/
83+
CfgNodes::ExprCfgNode getPostUpdateReverseStep(CfgNodes::ExprCfgNode e) {
84+
result = getALastEvalNode(e)
7385
}
7486

7587
/** Gets the SSA definition node corresponding to parameter `p`. */
@@ -170,6 +182,9 @@ module LocalFlow {
170182
)
171183
or
172184
nodeTo.(ImplicitBlockArgumentNode).getParameterNode(true) = nodeFrom
185+
or
186+
nodeTo.(PostUpdateNode).getPreUpdateNode().asExpr() =
187+
getPostUpdateReverseStep(nodeFrom.(PostUpdateNode).getPreUpdateNode().asExpr())
173188
}
174189

175190
predicate flowSummaryLocalStep(
@@ -486,7 +501,9 @@ private module Cached {
486501
// filter out nodes that clearly don't need post-update nodes
487502
isNonConstantExpr(n) and
488503
(
489-
n = getAPostUpdateNodeForArg(_)
504+
n instanceof Argument
505+
or
506+
n = getPostUpdateReverseStep(any(PostUpdateNode p).getPreUpdateNode().asExpr())
490507
or
491508
n = any(CfgNodes::ExprNodes::InstanceVariableAccessCfgNode v).getReceiver()
492509
)
@@ -2018,18 +2035,7 @@ private module PostUpdateNodes {
20182035

20192036
ExprPostUpdateNode() { this = TExprPostUpdateNode(e) }
20202037

2021-
override ExprNode getPreUpdateNode() {
2022-
// For compound arguments, such as `m(if b then x else y)`, we want the leaf nodes
2023-
// `[post] x` and `[post] y` to have two pre-update nodes: (1) the compound argument,
2024-
// `if b then x else y`; and the (2) the underlying expressions; `x` and `y`,
2025-
// respectively.
2026-
//
2027-
// This ensures that we get flow out of the call into both leafs (1), while still
2028-
// maintaining the invariant that the underlying expression is a pre-update node (2).
2029-
e = getAPostUpdateNodeForArg(result.getExprNode())
2030-
or
2031-
e = result.getExprNode()
2032-
}
2038+
override ExprNode getPreUpdateNode() { e = result.getExprNode() }
20332039

20342040
override CfgScope getCfgScope() { result = e.getExpr().getCfgScope() }
20352041

0 commit comments

Comments
 (0)