@@ -7,7 +7,9 @@ private import codeql.util.Unit
77private import codeql.dataflow.DataFlow
88private import codeql.dataflow.internal.DataFlowImpl
99private import rust
10+ private import SsaImpl as SsaImpl
1011private import codeql.rust.controlflow.ControlFlowGraph
12+ private import codeql.rust.controlflow.CfgNodes
1113private import codeql.rust.dataflow.Ssa
1214
1315module Node {
@@ -52,22 +54,67 @@ module Node {
5254 override Location getLocation ( ) { none ( ) }
5355 }
5456
57+ /**
58+ * A node in the data flow graph that corresponds to an expression in the
59+ * AST.
60+ *
61+ * Note that because of control-flow splitting, one `Expr` may correspond
62+ * to multiple `ExprNode`s, just like it may correspond to multiple
63+ * `ControlFlow::Node`s.
64+ */
65+ final class ExprNode extends Node , TExprNode {
66+ ExprCfgNode n ;
67+
68+ ExprNode ( ) { this = TExprNode ( n ) }
69+
70+ override Location getLocation ( ) { result = n .getExpr ( ) .getLocation ( ) }
71+
72+ override string toString ( ) { result = n .getExpr ( ) .toString ( ) }
73+
74+ override Expr asExpr ( ) { result = n .getExpr ( ) }
75+
76+ override CfgNode getCfgNode ( ) { result = n }
77+ }
78+
5579 /**
5680 * The value of a parameter at function entry, viewed as a node in a data
5781 * flow graph.
5882 */
59- final class ParameterNode extends Node {
60- Param param ;
83+ final class ParameterNode extends Node , TParameterNode {
84+ Param parameter ;
85+
86+ ParameterNode ( ) { this = TParameterNode ( parameter ) }
6187
62- ParameterNode ( ) { this = TSourceParameterNode ( param ) }
88+ override Location getLocation ( ) { result = parameter . getLocation ( ) }
6389
64- override Location getLocation ( ) { result = param . getLocation ( ) }
90+ override string toString ( ) { result = parameter . toString ( ) }
6591
66- override string toString ( ) { result = param .toString ( ) }
92+ /** Gets the parameter in the AST that this node corresponds to. */
93+ Param getParameter ( ) { result = parameter }
6794 }
6895
6996 final class ArgumentNode = NaNode ;
7097
98+ /** An SSA node. */
99+ class SsaNode extends Node , TSsaNode {
100+ SsaImpl:: DataFlowIntegration:: SsaNode node ;
101+ SsaImpl:: DefinitionExt def ;
102+
103+ SsaNode ( ) {
104+ this = TSsaNode ( node ) and
105+ def = node .getDefinitionExt ( )
106+ }
107+
108+ SsaImpl:: DefinitionExt getDefinitionExt ( ) { result = def }
109+
110+ /** Holds if this node should be hidden from path explanations. */
111+ abstract predicate isHidden ( ) ;
112+
113+ override Location getLocation ( ) { result = node .getLocation ( ) }
114+
115+ override string toString ( ) { result = node .toString ( ) }
116+ }
117+
71118 final class ReturnNode extends NaNode {
72119 RustDataFlow:: ReturnKind getKind ( ) { none ( ) }
73120 }
@@ -93,6 +140,64 @@ module Node {
93140 final class CastNode = NaNode ;
94141}
95142
143+ final class Node = Node:: Node ;
144+
145+ /** Provides logic related to SSA. */
146+ module SsaFlow {
147+ private module Impl = SsaImpl:: DataFlowIntegration;
148+
149+ private Node:: ParameterNode toParameterNode ( Param p ) { result = TParameterNode ( p ) }
150+
151+ /** Converts a control flow node into an SSA control flow node. */
152+ Impl:: Node asNode ( Node n ) {
153+ n = TSsaNode ( result )
154+ or
155+ result .( Impl:: ExprNode ) .getExpr ( ) = n .( Node:: ExprNode ) .getCfgNode ( )
156+ or
157+ n = toParameterNode ( result .( Impl:: ParameterNode ) .getParameter ( ) )
158+ }
159+
160+ predicate localFlowStep ( SsaImpl:: DefinitionExt def , Node nodeFrom , Node nodeTo , boolean isUseStep ) {
161+ Impl:: localFlowStep ( def , asNode ( nodeFrom ) , asNode ( nodeTo ) , isUseStep )
162+ }
163+
164+ predicate localMustFlowStep ( SsaImpl:: DefinitionExt def , Node nodeFrom , Node nodeTo ) {
165+ Impl:: localMustFlowStep ( def , asNode ( nodeFrom ) , asNode ( nodeTo ) )
166+ }
167+ }
168+
169+ /**
170+ * Holds for expressions `e` that evaluate to the value of any last (in
171+ * evaluation order) subexpressions within it. E.g., expressions that propagate
172+ * a values from a subexpression.
173+ *
174+ * For instance, the predicate holds for if expressions as `if b { e1 } else {
175+ * e2 }` evalates to the value of one of the subexpressions `e1` or `e2`.
176+ */
177+ private predicate propagatesValue ( Expr e ) {
178+ e instanceof IfExpr or
179+ e instanceof LoopExpr or
180+ e instanceof ReturnExpr or
181+ e instanceof BreakExpr or
182+ e .( BlockExpr ) .getStmtList ( ) .hasTailExpr ( ) or
183+ e instanceof MatchExpr
184+ }
185+
186+ /**
187+ * Gets a node that may execute last in `n`, and which, when it executes last,
188+ * will be the value of `n`.
189+ */
190+ private ExprCfgNode getALastEvalNode ( ExprCfgNode n ) {
191+ propagatesValue ( n .getExpr ( ) ) and result .getASuccessor ( ) = n
192+ }
193+
194+ module LocalFlow {
195+ pragma [ nomagic]
196+ predicate localFlowStepCommon ( Node nodeFrom , Node nodeTo ) {
197+ nodeFrom .getCfgNode ( ) = getALastEvalNode ( nodeTo .getCfgNode ( ) )
198+ }
199+ }
200+
96201module RustDataFlow implements InputSig< Location > {
97202 /**
98203 * An element, viewed as a node in a data flow graph. Either an expression
@@ -122,10 +227,10 @@ module RustDataFlow implements InputSig<Location> {
122227
123228 predicate nodeIsHidden ( Node node ) { none ( ) }
124229
125- class DataFlowExpr = Void ;
230+ class DataFlowExpr = ExprCfgNode ;
126231
127232 /** Gets the node corresponding to `e`. */
128- Node exprNode ( DataFlowExpr e ) { none ( ) }
233+ Node exprNode ( DataFlowExpr e ) { result . getCfgNode ( ) = e }
129234
130235 final class DataFlowCall extends TNormalCall {
131236 private CallExpr c ;
@@ -191,7 +296,7 @@ module RustDataFlow implements InputSig<Location> {
191296 * Holds if there is a simple local flow step from `node1` to `node2`. These
192297 * are the value-preserving intra-callable flow steps.
193298 */
194- predicate simpleLocalFlowStep ( Node node1 , Node node2 , string model ) { none ( ) }
299+ predicate simpleLocalFlowStep ( Node nodeFrom , Node nodeTo , string model ) { none ( ) }
195300
196301 /**
197302 * Holds if data can flow from `node1` to `node2` through a non-local step
@@ -256,7 +361,9 @@ module RustDataFlow implements InputSig<Location> {
256361 * `node2` must be visited along a flow path, then any type known for `node2`
257362 * must also apply to `node1`.
258363 */
259- predicate localMustFlowStep ( Node node1 , Node node2 ) { none ( ) }
364+ predicate localMustFlowStep ( Node node1 , Node node2 ) {
365+ SsaFlow:: localMustFlowStep ( _, node1 , node2 )
366+ }
260367
261368 class LambdaCallKind = Void ;
262369
@@ -267,7 +374,7 @@ module RustDataFlow implements InputSig<Location> {
267374 /** Holds if `call` is a lambda call of kind `kind` where `receiver` is the lambda expression. */
268375 predicate lambdaCall ( DataFlowCall call , LambdaCallKind kind , Node receiver ) { none ( ) }
269376
270- /** Extra data- flow steps needed for lambda flow analysis. */
377+ /** Extra data flow steps needed for lambda flow analysis. */
271378 predicate additionalLambdaFlowStep ( Node nodeFrom , Node nodeTo , boolean preservesValue ) { none ( ) }
272379
273380 predicate knownSourceModel ( Node source , string model ) { none ( ) }
@@ -286,8 +393,9 @@ cached
286393private module Cached {
287394 cached
288395 newtype TNode =
289- TExprNode ( CfgNode n , Expr e ) { n .getAstNode ( ) = e } or
290- TSourceParameterNode ( Param param )
396+ TExprNode ( ExprCfgNode n ) or
397+ TParameterNode ( Param p ) or
398+ TSsaNode ( SsaImpl:: DataFlowIntegration:: SsaNode node )
291399
292400 cached
293401 newtype TDataFlowCall = TNormalCall ( CallExpr c )
@@ -302,7 +410,11 @@ private module Cached {
302410
303411 /** This is the local flow predicate that is exposed. */
304412 cached
305- predicate localFlowStepImpl ( Node:: Node nodeFrom , Node:: Node nodeTo ) { none ( ) }
413+ predicate localFlowStepImpl ( Node:: Node nodeFrom , Node:: Node nodeTo ) {
414+ LocalFlow:: localFlowStepCommon ( nodeFrom , nodeTo )
415+ or
416+ SsaFlow:: localFlowStep ( _, nodeFrom , nodeTo , _)
417+ }
306418}
307419
308420import Cached
0 commit comments