@@ -15,6 +15,7 @@ private import codeql.rust.controlflow.CfgNodes
1515private import codeql.rust.dataflow.Ssa
1616private import codeql.rust.dataflow.FlowSummary
1717private import codeql.rust.internal.TypeInference as TypeInference
18+ private import codeql.rust.internal.typeinference.DerefChain
1819private import Node as Node
1920private import DataFlowImpl
2021private import FlowSummaryImpl as FlowSummaryImpl
@@ -229,47 +230,152 @@ final class ExprArgumentNode extends ArgumentNode, ExprNode {
229230
230231 ExprArgumentNode ( ) {
231232 isArgumentForCall ( n , call_ , pos_ ) and
232- not TypeInference:: implicitDeref ( n ) and
233- not TypeInference:: implicitBorrow ( n , _)
233+ not TypeInference:: implicitDerefChainBorrow ( n , _, _)
234234 }
235235
236236 override predicate isArgumentOf ( DataFlowCall call , RustDataFlow:: ArgumentPosition pos ) {
237237 call .asCall ( ) = call_ and pos = pos_
238238 }
239239}
240240
241+ private newtype TImplicitDerefNodeState =
242+ TImplicitDerefNodeBorrowState ( ) or
243+ TImplicitDerefNodeBeforeDerefState ( ) or
244+ TImplicitDerefNodeAfterDerefState ( )
245+
246+ /**
247+ * A state used to represent the flow steps involved in implicit dereferencing.
248+ *
249+ * For example, if there is an implicit dereference in a call like `x.m()`,
250+ * then that desugars into `(*Deref::deref(&x)).m()`, and
251+ *
252+ * - `TImplicitDerefNodeBorrowState` represents the `&x` part,
253+ * - `TImplicitDerefNodeBeforeDerefState` represents the `Deref::deref(&x)` part, and
254+ * - `TImplicitDerefNodeAfterDerefState` represents the entire `*Deref::deref(&x)` part.
255+ */
256+ class ImplicitDerefNodeState extends TImplicitDerefNodeState {
257+ string toString ( ) {
258+ this = TImplicitDerefNodeBorrowState ( ) and result = "borrow"
259+ or
260+ this = TImplicitDerefNodeBeforeDerefState ( ) and result = "before deref"
261+ or
262+ this = TImplicitDerefNodeAfterDerefState ( ) and result = "after deref"
263+ }
264+ }
265+
241266/**
242- * A node that represents the value of an expression _after_ implicit dereferencing
243- * or borrowing.
267+ * A node used to represent implicit dereferencing.
244268 */
245- class DerefBorrowNode extends Node , TDerefBorrowNode {
269+ class ImplicitDerefNode extends Node , TImplicitDerefNode {
246270 AstNode n ;
247- boolean isBorrow ;
271+ DerefChain derefChain ;
272+ ImplicitDerefNodeState state ;
273+ int i ;
248274
249- DerefBorrowNode ( ) { this = TDerefBorrowNode ( n , isBorrow , false ) }
275+ ImplicitDerefNode ( ) { this = TImplicitDerefNode ( n , derefChain , state , i , false ) }
250276
251- AstNode getNode ( ) { result = n }
277+ /**
278+ * Gets the node that should the predecessor in a reference store-step into this
279+ * node, if any.
280+ */
281+ Node getBorrowInputNode ( ) {
282+ state = TImplicitDerefNodeBorrowState ( ) and
283+ (
284+ i = 0 and
285+ result .( AstNodeNode ) .getAstNode ( ) = n
286+ or
287+ result = TImplicitDerefNode ( n , derefChain , TImplicitDerefNodeAfterDerefState ( ) , i - 1 , false )
288+ )
289+ }
252290
253- predicate isBorrow ( ) { isBorrow = true }
291+ /**
292+ * Gets the node that should the successor in a reference read-step out of this
293+ * node, if any.
294+ */
295+ Node getDerefOutputNode ( ) {
296+ state = TImplicitDerefNodeBeforeDerefState ( ) and
297+ result = TImplicitDerefNode ( n , derefChain , TImplicitDerefNodeAfterDerefState ( ) , i , false )
298+ }
299+
300+ predicate isLast ( AstNode node ) {
301+ node = n and
302+ state = TImplicitDerefNodeAfterDerefState ( ) and
303+ i = derefChain .length ( ) - 1
304+ }
254305
255306 override CfgScope getCfgScope ( ) { result = n .getEnclosingCfgScope ( ) }
256307
257308 override Location getLocation ( ) { result = n .getLocation ( ) }
258309
259- override string toString ( ) {
260- if isBorrow = true then result = n + " [borrowed]" else result = n + " [dereferenced]"
310+ override string toString ( ) { result = n + " [implicit deref " + i + " in state " + state + "]" }
311+ }
312+
313+ final class ImplicitDerefArgNode extends ImplicitDerefNode , ArgumentNode {
314+ private DataFlowCall call_ ;
315+ private RustDataFlow:: ArgumentPosition pos_ ;
316+
317+ ImplicitDerefArgNode ( ) {
318+ state = TImplicitDerefNodeBorrowState ( ) and
319+ call_ = TImplicitDerefCall ( n , derefChain , i , _) and
320+ pos_ .isSelf ( )
321+ or
322+ this .isLast ( _) and
323+ TypeInference:: implicitDerefChainBorrow ( n , derefChain , false ) and
324+ isArgumentForCall ( n , call_ .asCall ( ) , pos_ )
325+ }
326+
327+ override predicate isArgumentOf ( DataFlowCall call , RustDataFlow:: ArgumentPosition pos ) {
328+ call = call_ and pos = pos_
329+ }
330+ }
331+
332+ private class ImplicitDerefOutNode extends ImplicitDerefNode , OutNode {
333+ private DataFlowCall call ;
334+
335+ ImplicitDerefOutNode ( ) { state = TImplicitDerefNodeBeforeDerefState ( ) }
336+
337+ override DataFlowCall getCall ( ReturnKind kind ) {
338+ result = TImplicitDerefCall ( n , derefChain , i , _) and
339+ kind = TNormalReturnKind ( )
261340 }
262341}
263342
264343/**
265- * A node that represents the value of an argument of a call _after_ implicit
266- * dereferencing or borrowing.
344+ * A node that represents the value of an expression _after_ implicit borrowing.
267345 */
268- final class DerefBorrowArgNode extends DerefBorrowNode , ArgumentNode {
346+ class ImplicitBorrowNode extends Node , TImplicitBorrowNode {
347+ AstNode n ;
348+ DerefChain derefChain ;
349+
350+ ImplicitBorrowNode ( ) { this = TImplicitBorrowNode ( n , derefChain , false ) }
351+
352+ AstNode getNode ( ) { result = n }
353+
354+ /**
355+ * Gets the node that should the predecessor in a reference store-step into this
356+ * node.
357+ */
358+ Node getBorrowInputNode ( ) {
359+ result =
360+ TImplicitDerefNode ( n , derefChain , TImplicitDerefNodeAfterDerefState ( ) ,
361+ derefChain .length ( ) - 1 , false )
362+ or
363+ derefChain .isEmpty ( ) and
364+ result .( AstNodeNode ) .getAstNode ( ) = n
365+ }
366+
367+ override CfgScope getCfgScope ( ) { result = n .getEnclosingCfgScope ( ) }
368+
369+ override Location getLocation ( ) { result = n .getLocation ( ) }
370+
371+ override string toString ( ) { result = n + " [implicit borrow]" }
372+ }
373+
374+ final class ImplicitBorrowArgNode extends ImplicitBorrowNode , ArgumentNode {
269375 private DataFlowCall call_ ;
270376 private RustDataFlow:: ArgumentPosition pos_ ;
271377
272- DerefBorrowArgNode ( ) { isArgumentForCall ( n , call_ .asCall ( ) , pos_ ) }
378+ ImplicitBorrowArgNode ( ) { isArgumentForCall ( n , call_ .asCall ( ) , pos_ ) }
273379
274380 override predicate isArgumentOf ( DataFlowCall call , RustDataFlow:: ArgumentPosition pos ) {
275381 call = call_ and pos = pos_
@@ -478,17 +584,36 @@ final class ExprPostUpdateNode extends PostUpdateNode, TExprPostUpdateNode {
478584 override Location getLocation ( ) { result = e .getLocation ( ) }
479585}
480586
481- final class DerefBorrowPostUpdateNode extends PostUpdateNode , TDerefBorrowNode {
482- private Expr arg ;
483- private boolean isBorrow ;
587+ final class ImplicitDerefPostUpdateNode extends PostUpdateNode , TImplicitDerefNode {
588+ AstNode n ;
589+ DerefChain derefChain ;
590+ ImplicitDerefNodeState state ;
591+ int i ;
592+
593+ ImplicitDerefPostUpdateNode ( ) { this = TImplicitDerefNode ( n , derefChain , state , i , true ) }
594+
595+ override ImplicitDerefNode getPreUpdateNode ( ) {
596+ result = TImplicitDerefNode ( n , derefChain , state , i , false )
597+ }
598+
599+ override CfgScope getCfgScope ( ) { result = n .getEnclosingCfgScope ( ) }
600+
601+ override Location getLocation ( ) { result = n .getLocation ( ) }
602+ }
603+
604+ final class ImplicitBorrowPostUpdateNode extends PostUpdateNode , TImplicitBorrowNode {
605+ AstNode n ;
606+ DerefChain derefChain ;
484607
485- DerefBorrowPostUpdateNode ( ) { this = TDerefBorrowNode ( arg , isBorrow , true ) }
608+ ImplicitBorrowPostUpdateNode ( ) { this = TImplicitBorrowNode ( n , derefChain , true ) }
486609
487- override DerefBorrowNode getPreUpdateNode ( ) { result = TDerefBorrowNode ( arg , isBorrow , false ) }
610+ override ImplicitBorrowNode getPreUpdateNode ( ) {
611+ result = TImplicitBorrowNode ( n , derefChain , false )
612+ }
488613
489- override CfgScope getCfgScope ( ) { result = arg .getEnclosingCfgScope ( ) }
614+ override CfgScope getCfgScope ( ) { result = n .getEnclosingCfgScope ( ) }
490615
491- override Location getLocation ( ) { result = arg .getLocation ( ) }
616+ override Location getLocation ( ) { result = n .getLocation ( ) }
492617}
493618
494619class DerefOutPostUpdateNode extends PostUpdateNode , TDerefOutNode {
@@ -575,12 +700,14 @@ newtype TNode =
575700 ]
576701 )
577702 } or
578- TDerefBorrowNode ( AstNode n , boolean borrow , Boolean isPost ) {
579- TypeInference:: implicitDeref ( n ) and
580- borrow = false
581- or
582- TypeInference:: implicitBorrow ( n , _) and
583- borrow = true
703+ TImplicitDerefNode (
704+ AstNode n , DerefChain derefChain , ImplicitDerefNodeState state , int i , Boolean isPost
705+ ) {
706+ TypeInference:: implicitDerefChainBorrow ( n , derefChain , _) and
707+ i in [ 0 .. derefChain .length ( ) - 1 ]
708+ } or
709+ TImplicitBorrowNode ( AstNode n , DerefChain derefChain , Boolean isPost ) {
710+ TypeInference:: implicitDerefChainBorrow ( n , derefChain , true )
584711 } or
585712 TDerefOutNode ( DerefExpr de , Boolean isPost ) or
586713 TIndexOutNode ( IndexExpr ie , Boolean isPost ) or
0 commit comments