@@ -2504,4 +2504,64 @@ module Reachability {
25042504 )
25052505 )
25062506 }
2507+
2508+ /**
2509+ * Holds if `var` is an SSA variable that is implicitly defined (a builtin,
2510+ * VM-defined name, or `__path__` in a package init).
2511+ */
2512+ private predicate implicitlyDefined ( SsaVariable var ) {
2513+ not exists ( var .getDefinition ( ) ) and
2514+ not py_ssa_phi ( var , _) and
2515+ exists ( GlobalVariable gv | var .getVariable ( ) = gv |
2516+ DuckTyping:: globallyDefinedName ( gv .getId ( ) )
2517+ or
2518+ gv .getId ( ) = "__path__" and gv .getScope ( ) .( Module ) .isPackageInit ( )
2519+ )
2520+ }
2521+
2522+ /**
2523+ * Gets a phi input of `var`, pruned of unlikely edges.
2524+ */
2525+ private SsaVariable getAPrunedPhiInput ( SsaVariable var ) {
2526+ result = var .getAPhiInput ( ) and
2527+ exists ( BasicBlock incoming | incoming = var .getPredecessorBlockForPhiArgument ( result ) |
2528+ not unlikelySuccessor ( incoming .getLastNode ( ) , var .getDefinition ( ) .getBasicBlock ( ) .firstNode ( ) )
2529+ )
2530+ }
2531+
2532+ /**
2533+ * Gets a predecessor block for a phi node, pruned of unlikely edges.
2534+ */
2535+ private BasicBlock getAPrunedPredecessorBlockForPhi ( SsaVariable var ) {
2536+ result = var .getAPredecessorBlockForPhi ( ) and
2537+ not unlikelySuccessor ( result .getLastNode ( ) , var .getDefinition ( ) .getBasicBlock ( ) .firstNode ( ) )
2538+ }
2539+
2540+ /**
2541+ * Holds if the SSA variable `var` may be undefined at some use.
2542+ */
2543+ private predicate ssaMaybeUndefined ( SsaVariable var ) {
2544+ // No definition, not a phi, not implicitly defined
2545+ not exists ( var .getDefinition ( ) ) and not py_ssa_phi ( var , _) and not implicitlyDefined ( var )
2546+ or
2547+ // Defined by a deletion
2548+ var .getDefinition ( ) .isDelete ( )
2549+ or
2550+ // A phi input may be undefined
2551+ exists ( SsaVariable input | input = getAPrunedPhiInput ( var ) | ssaMaybeUndefined ( input ) )
2552+ or
2553+ // A phi predecessor has no dominating definition
2554+ exists ( BasicBlock incoming |
2555+ likelyReachable ( incoming ) and
2556+ incoming = getAPrunedPredecessorBlockForPhi ( var ) and
2557+ not var .getAPhiInput ( ) .getDefinition ( ) .getBasicBlock ( ) .dominates ( incoming )
2558+ )
2559+ }
2560+
2561+ /**
2562+ * Holds if the name `u` may be undefined at its use.
2563+ */
2564+ predicate maybeUndefined ( Name u ) {
2565+ exists ( SsaVariable var | var .getAUse ( ) .getNode ( ) = u | ssaMaybeUndefined ( var ) )
2566+ }
25072567}
0 commit comments