@@ -17,6 +17,7 @@ private import semmle.python.Frameworks
17
17
import MatchUnpacking
18
18
import IterableUnpacking
19
19
import DataFlowDispatch
20
+ import VariableCapture as VariableCapture
20
21
21
22
/** Gets the callable in which this node occurs. */
22
23
DataFlowCallable nodeGetEnclosingCallable ( Node n ) { result = n .getEnclosingCallable ( ) }
@@ -384,197 +385,6 @@ module LocalFlow {
384
385
}
385
386
}
386
387
387
- /** Provides logic related to captured variables. */
388
- module VariableCapture {
389
- private import codeql.dataflow.VariableCapture as Shared
390
-
391
- private module CaptureInput implements Shared:: InputSig< Location > {
392
- private import python as PY
393
-
394
- additional class ExprCfgNode extends ControlFlowNode {
395
- ExprCfgNode ( ) { isExpressionNode ( this ) }
396
- }
397
-
398
- private predicate closureFlowStep ( ExprCfgNode nodeFrom , ExprCfgNode nodeTo ) {
399
- // TODO: Other languages have an extra case here looking like
400
- // simpleAstFlowStep(nodeFrom, nodeTo)
401
- // we should investigate the potential benefit of adding that.
402
- exists ( SsaVariable def |
403
- def .getAUse ( ) = nodeTo and
404
- def .getAnUltimateDefinition ( ) .getDefinition ( ) .( DefinitionNode ) .getValue ( ) = nodeFrom
405
- )
406
- }
407
-
408
- class Callable extends Scope {
409
- predicate isConstructor ( ) { none ( ) }
410
- }
411
-
412
- class BasicBlock extends PY:: BasicBlock {
413
- Callable getEnclosingCallable ( ) { result = this .getScope ( ) }
414
-
415
- // TODO: check that this gives useful results
416
- Location getLocation ( ) { result = super .getNode ( 0 ) .getLocation ( ) }
417
- }
418
-
419
- BasicBlock getImmediateBasicBlockDominator ( BasicBlock bb ) {
420
- result = bb .getImmediateDominator ( )
421
- }
422
-
423
- BasicBlock getABasicBlockSuccessor ( BasicBlock bb ) { result = bb .getASuccessor ( ) }
424
-
425
- class CapturedVariable extends LocalVariable {
426
- Function f ;
427
-
428
- CapturedVariable ( ) {
429
- // note: captured variables originating on module scope is currently
430
- // covered by global variable handling.
431
- this .getScope ( ) = f and
432
- this .getAnAccess ( ) .getScope ( ) != f
433
- }
434
-
435
- Callable getCallable ( ) { result = f }
436
-
437
- Location getLocation ( ) { result = f .getLocation ( ) }
438
-
439
- /** Gets a scope that captures this variable. */
440
- Scope getACapturingScope ( ) {
441
- result = this .getAnAccess ( ) .getScope ( ) .getScope * ( ) and
442
- result .getScope + ( ) = f
443
- }
444
- }
445
-
446
- class CapturedParameter extends CapturedVariable {
447
- CapturedParameter ( ) { this .isParameter ( ) }
448
-
449
- ControlFlowNode getCfgNode ( ) { result .getNode ( ) .( Parameter ) = this .getAnAccess ( ) }
450
- }
451
-
452
- class Expr extends ExprCfgNode {
453
- predicate hasCfgNode ( BasicBlock bb , int i ) { this = bb .getNode ( i ) }
454
- }
455
-
456
- class VariableWrite extends ControlFlowNode {
457
- CapturedVariable v ;
458
-
459
- VariableWrite ( ) { this = v .getAStore ( ) .getAFlowNode ( ) }
460
-
461
- CapturedVariable getVariable ( ) { result = v }
462
-
463
- predicate hasCfgNode ( BasicBlock bb , int i ) { this = bb .getNode ( i ) }
464
- }
465
-
466
- class VariableRead extends Expr {
467
- CapturedVariable v ;
468
-
469
- VariableRead ( ) { this = v .getALoad ( ) .getAFlowNode ( ) }
470
-
471
- CapturedVariable getVariable ( ) { result = v }
472
- }
473
-
474
- class ClosureExpr extends Expr {
475
- ClosureExpr ( ) {
476
- this .getNode ( ) instanceof CallableExpr
477
- or
478
- this .getNode ( ) instanceof Comp
479
- }
480
-
481
- predicate hasBody ( Callable body ) {
482
- body = this .getNode ( ) .( CallableExpr ) .getInnerScope ( )
483
- or
484
- body = this .getNode ( ) .( Comp ) .getFunction ( )
485
- }
486
-
487
- predicate hasAliasedAccess ( Expr f ) { closureFlowStep + ( this , f ) and not closureFlowStep ( f , _) }
488
- }
489
- }
490
-
491
- class CapturedVariable = CaptureInput:: CapturedVariable ;
492
-
493
- class ClosureExpr = CaptureInput:: ClosureExpr ;
494
-
495
- module Flow = Shared:: Flow< Location , CaptureInput > ;
496
-
497
- private Flow:: ClosureNode asClosureNode ( Node n ) {
498
- result = n .( SynthCaptureNode ) .getSynthesizedCaptureNode ( )
499
- or
500
- result .( Flow:: ExprNode ) .getExpr ( ) = n .( CfgNode ) .getNode ( )
501
- or
502
- result .( Flow:: VariableWriteSourceNode ) .getVariableWrite ( ) = n .( CfgNode ) .getNode ( )
503
- or
504
- result .( Flow:: ExprPostUpdateNode ) .getExpr ( ) =
505
- n .( PostUpdateNode ) .getPreUpdateNode ( ) .( CfgNode ) .getNode ( )
506
- or
507
- result .( Flow:: ParameterNode ) .getParameter ( ) .getCfgNode ( ) = n .( CfgNode ) .getNode ( )
508
- or
509
- result .( Flow:: ThisParameterNode ) .getCallable ( ) =
510
- n .( SynthCapturingClosureParameterNode ) .getCallable ( )
511
- }
512
-
513
- predicate storeStep ( Node nodeFrom , CapturedVariableContent c , Node nodeTo ) {
514
- Flow:: storeStep ( asClosureNode ( nodeFrom ) , c .getVariable ( ) , asClosureNode ( nodeTo ) )
515
- }
516
-
517
- predicate readStep ( Node nodeFrom , CapturedVariableContent c , Node nodeTo ) {
518
- Flow:: readStep ( asClosureNode ( nodeFrom ) , c .getVariable ( ) , asClosureNode ( nodeTo ) )
519
- }
520
-
521
- predicate valueStep ( Node nodeFrom , Node nodeTo ) {
522
- Flow:: localFlowStep ( asClosureNode ( nodeFrom ) , asClosureNode ( nodeTo ) )
523
- }
524
-
525
- // Note: Learn from JS, https://github.com/github/codeql/pull/14412
526
- // - JS: Capture flow
527
- // - JS: Disallow consecutive captured contents
528
- private module Debug {
529
- predicate flowStoreStep (
530
- Node nodeFrom , Flow:: ClosureNode closureNodeFrom , CapturedVariable v ,
531
- Flow:: ClosureNode closureNodeTo , Node nodeTo
532
- ) {
533
- closureNodeFrom = asClosureNode ( nodeFrom ) and
534
- closureNodeTo = asClosureNode ( nodeTo ) and
535
- Flow:: storeStep ( closureNodeFrom , v , closureNodeTo )
536
- }
537
-
538
- predicate unmappedFlowStoreStep (
539
- Flow:: ClosureNode closureNodeFrom , CapturedVariable v , Flow:: ClosureNode closureNodeTo
540
- ) {
541
- Flow:: storeStep ( closureNodeFrom , v , closureNodeTo ) and
542
- not flowStoreStep ( _, closureNodeFrom , v , closureNodeTo , _)
543
- }
544
-
545
- predicate flowReadStep (
546
- Node nodeFrom , Flow:: ClosureNode closureNodeFrom , CapturedVariable v ,
547
- Flow:: ClosureNode closureNodeTo , Node nodeTo
548
- ) {
549
- closureNodeFrom = asClosureNode ( nodeFrom ) and
550
- closureNodeTo = asClosureNode ( nodeTo ) and
551
- Flow:: readStep ( closureNodeFrom , v , closureNodeTo )
552
- }
553
-
554
- predicate unmappedFlowReadStep (
555
- Flow:: ClosureNode closureNodeFrom , CapturedVariable v , Flow:: ClosureNode closureNodeTo
556
- ) {
557
- Flow:: readStep ( closureNodeFrom , v , closureNodeTo ) and
558
- not flowReadStep ( _, closureNodeFrom , v , closureNodeTo , _)
559
- }
560
-
561
- predicate flowValueStep (
562
- Node nodeFrom , Flow:: ClosureNode closureNodeFrom , Flow:: ClosureNode closureNodeTo , Node nodeTo
563
- ) {
564
- closureNodeFrom = asClosureNode ( nodeFrom ) and
565
- closureNodeTo = asClosureNode ( nodeTo ) and
566
- Flow:: localFlowStep ( closureNodeFrom , closureNodeTo )
567
- }
568
-
569
- predicate unmappedFlowValueStep (
570
- Flow:: ClosureNode closureNodeFrom , Flow:: ClosureNode closureNodeTo
571
- ) {
572
- Flow:: localFlowStep ( closureNodeFrom , closureNodeTo ) and
573
- not flowValueStep ( _, closureNodeFrom , closureNodeTo , _)
574
- }
575
- }
576
- }
577
-
578
388
//--------
579
389
// Local flow
580
390
//--------
0 commit comments