@@ -66,10 +66,22 @@ private CfgNodes::ExprCfgNode getALastEvalNode(CfgNodes::ExprCfgNode n) {
66
66
)
67
67
}
68
68
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 )
73
85
}
74
86
75
87
/** Gets the SSA definition node corresponding to parameter `p`. */
@@ -170,6 +182,9 @@ module LocalFlow {
170
182
)
171
183
or
172
184
nodeTo .( ImplicitBlockArgumentNode ) .getParameterNode ( true ) = nodeFrom
185
+ or
186
+ nodeTo .( PostUpdateNode ) .getPreUpdateNode ( ) .asExpr ( ) =
187
+ getPostUpdateReverseStep ( nodeFrom .( PostUpdateNode ) .getPreUpdateNode ( ) .asExpr ( ) )
173
188
}
174
189
175
190
predicate flowSummaryLocalStep (
@@ -486,7 +501,9 @@ private module Cached {
486
501
// filter out nodes that clearly don't need post-update nodes
487
502
isNonConstantExpr ( n ) and
488
503
(
489
- n = getAPostUpdateNodeForArg ( _)
504
+ n instanceof Argument
505
+ or
506
+ n = getPostUpdateReverseStep ( any ( PostUpdateNode p ) .getPreUpdateNode ( ) .asExpr ( ) )
490
507
or
491
508
n = any ( CfgNodes:: ExprNodes:: InstanceVariableAccessCfgNode v ) .getReceiver ( )
492
509
)
@@ -2018,18 +2035,7 @@ private module PostUpdateNodes {
2018
2035
2019
2036
ExprPostUpdateNode ( ) { this = TExprPostUpdateNode ( e ) }
2020
2037
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 ( ) }
2033
2039
2034
2040
override CfgScope getCfgScope ( ) { result = e .getExpr ( ) .getCfgScope ( ) }
2035
2041
0 commit comments