@@ -417,7 +417,7 @@ cached module PointsToInternal {
417417 or
418418 attribute_delete_points_to ( def , context , value , origin )
419419 or
420- uni_edged_phi_points_to ( def , context , value , origin )
420+ uni_edged_pi_points_to ( def , context , value , origin )
421421 }
422422
423423 /** Pass through for `self` for the implicit re-definition of `self` in `self.foo()`. */
@@ -460,16 +460,16 @@ cached module PointsToInternal {
460460 result = Conditionals:: testEvaluates ( def .getTest ( ) , def .getInput ( ) .getASourceUse ( ) , context , value , origin )
461461 }
462462
463- /** Holds if ESSA definition, `uniphi `, refers to `(value, origin)`. */
463+ /** Holds if ESSA definition, `unipi `, refers to `(value, origin)`. */
464464 pragma [ noinline]
465- private predicate uni_edged_phi_points_to ( SingleSuccessorGuard uniphi , PointsToContext context , ObjectInternal value , CfgOrigin origin ) {
466- exists ( ControlFlowNode test , ControlFlowNode use |
465+ private predicate uni_edged_pi_points_to ( SingleSuccessorGuard unipi , PointsToContext context , ObjectInternal value , CfgOrigin origin ) {
466+ exists ( ControlFlowNode test , ControlFlowNode use , ControlFlowNode orig |
467467 /* Because calls such as `len` may create a new variable, we need to go via the source variable
468468 * That is perfectly safe as we are only dealing with calls that do not mutate their arguments.
469469 */
470- use = uniphi . getInput ( ) . getASourceUse ( ) and
471- test = uniphi . getTest ( ) and
472- uniphi . getSense ( ) = Conditionals :: testEvaluates ( test , use , context , value , origin . toCfgNode ( ) )
470+ unipi . useAndTest ( use , test ) and
471+ unipi . getSense ( ) = Conditionals :: testEvaluates ( test , use , context , value , orig ) and
472+ origin = CfgOrigin :: fromCfgNode ( orig )
473473 )
474474 }
475475
@@ -785,7 +785,28 @@ module InterProceduralPointsTo {
785785 }
786786
787787 pragma [ noinline]
788- private predicate call_points_to_simple ( CallNode f , PointsToContext context , ObjectInternal value , ControlFlowNode origin ) {
788+ predicate call_points_to ( CallNode f , PointsToContext context , ObjectInternal value , ControlFlowNode origin ) {
789+ /* Either not a decorator, or we understand the return value */
790+ ( value != ObjectInternal:: unknown ( ) or not f .isDecoratorCall ( ) ) and
791+ call_points_to_from_callee ( f , context , value , origin )
792+ or
793+ call_result_is_first_argument ( f , context ) and
794+ PointsToInternal:: pointsTo ( f .getArg ( 0 ) , context , value , origin )
795+ or
796+ Expressions:: typeCallPointsTo ( f , context , value , origin , _, _)
797+ }
798+
799+ /** Helper for call_points_to to improve join-order */
800+ private predicate call_result_is_first_argument ( CallNode f , PointsToContext context ) {
801+ Types:: six_add_metaclass ( f , context , _, _)
802+ or
803+ /* A decorator and we don't understand it. Use the original, undecorated value */
804+ f .isDecoratorCall ( ) and call_points_to_from_callee ( f , context , ObjectInternal:: unknown ( ) , _)
805+ }
806+
807+ /** Helper for call_points_to to improve join-order */
808+ pragma [ noinline]
809+ private predicate call_points_to_from_callee ( CallNode f , PointsToContext context , ObjectInternal value , ControlFlowNode origin ) {
789810 exists ( ObjectInternal func |
790811 call ( f , context , func )
791812 |
@@ -806,27 +827,6 @@ module InterProceduralPointsTo {
806827 )
807828 }
808829
809- pragma [ noinline]
810- predicate call_points_to ( CallNode f , PointsToContext context , ObjectInternal value , ControlFlowNode origin ) {
811- /* Either not a decorator, or we understand the return value */
812- ( value != ObjectInternal:: unknown ( ) or not f .isDecoratorCall ( ) ) and
813- call_points_to_simple ( f , context , value , origin )
814- or
815- call_result_is_first_argument ( f , context ) and
816- PointsToInternal:: pointsTo ( f .getArg ( 0 ) , context , value , origin )
817- or
818- Expressions:: typeCallPointsTo ( f , context , value , origin , _, _)
819- }
820-
821- /** Helper for call_points_to to improve join-order */
822- private predicate call_result_is_first_argument ( CallNode f , PointsToContext context ) {
823- Types:: six_add_metaclass ( f , context , _, _)
824- or
825- /* A decorator and we don't understand it. Use the original, undecorated value */
826- f .isDecoratorCall ( ) and call_points_to_simple ( f , context , ObjectInternal:: unknown ( ) , _)
827- }
828-
829-
830830 /** Points-to for parameter. `def foo(param): ...`. */
831831 pragma [ noinline]
832832 predicate parameter_points_to ( ParameterDefinition def , PointsToContext context , ObjectInternal value , ControlFlowNode origin ) {
@@ -898,26 +898,27 @@ module InterProceduralPointsTo {
898898 /** Helper for parameter_points_to */
899899 pragma [ noinline]
900900 private predicate special_parameter_points_to ( ParameterDefinition def , PointsToContext context , ObjectInternal value , ControlFlowNode origin ) {
901- (
902- def .isVarargs ( ) and value = TUnknownInstance ( ObjectInternal:: builtin ( "tuple" ) )
903- or
904- def .isKwargs ( ) and value = TUnknownInstance ( ObjectInternal:: builtin ( "dict" ) )
905- )
906- and
901+ special_parameter_value ( def , value ) and
907902 (
908903 context .isRuntime ( )
909904 or
910- exists ( PointsToContext caller , CallNode call , Parameter p |
905+ exists ( PointsToContext caller , CallNode call |
911906 context .fromCall ( call , caller ) and
912907 context .appliesToScope ( def .getScope ( ) ) and
913- p = def .getParameter ( ) and
914- not exists ( call .getArg ( p .getPosition ( ) ) ) and
915- not exists ( call .getArgByName ( p .getName ( ) ) )
908+ not exists ( call .getArg ( def .getParameter ( ) .getPosition ( ) ) ) and
909+ not exists ( call .getArgByName ( def .getParameter ( ) .getName ( ) ) )
916910 )
917911 ) and
918912 origin = def .getDefiningNode ( )
919913 }
920914
915+ /** Helper predicate for special_parameter_points_to */
916+ private predicate special_parameter_value ( ParameterDefinition p , ObjectInternal value ) {
917+ p .isVarargs ( ) and value = TUnknownInstance ( ObjectInternal:: builtin ( "tuple" ) )
918+ or
919+ p .isKwargs ( ) and value = TUnknownInstance ( ObjectInternal:: builtin ( "dict" ) )
920+ }
921+
921922 /** Holds if the `(argument, caller)` pair matches up with `(param, callee)` pair across call. */
922923 cached predicate callsite_argument_transfer ( ControlFlowNode argument , PointsToContext caller , ParameterDefinition param , PointsToContext callee ) {
923924 exists ( CallNode call , Function func , int offset |
@@ -1178,10 +1179,7 @@ module Expressions {
11781179
11791180 pragma [ noinline]
11801181 predicate typeCallPointsTo ( CallNode call , PointsToContext context , ObjectInternal value , ControlFlowNode origin , ControlFlowNode arg , ObjectInternal argvalue ) {
1181- not exists ( call .getArg ( 1 ) ) and
1182- arg = call .getArg ( 0 ) and
1183- InterProceduralPointsTo:: call ( call , context , ObjectInternal:: builtin ( "type" ) ) and
1184- PointsToInternal:: pointsTo ( arg , context , argvalue , _) and
1182+ type_call1 ( call , arg , context , argvalue ) and
11851183 value = argvalue .getClass ( ) and
11861184 origin = CfgOrigin:: fromObject ( value ) .asCfgNodeOrHere ( call )
11871185 }
@@ -1467,6 +1465,13 @@ module Expressions {
14671465 PointsToInternal:: pointsTo ( use , context , val , _)
14681466 }
14691467
1468+ private predicate type_call1 ( CallNode call , ControlFlowNode use , PointsToContext context , ObjectInternal val ) {
1469+ PointsToInternal:: pointsTo ( call .getFunction ( ) , context , ObjectInternal:: builtin ( "type" ) , _) and
1470+ use = call .getArg ( 0 ) and
1471+ not exists ( call .getArg ( 1 ) ) and
1472+ PointsToInternal:: pointsTo ( use , context , val , _)
1473+ }
1474+
14701475 private predicate hasattr_call ( CallNode call , ControlFlowNode use , PointsToContext context , ObjectInternal val , string name ) {
14711476 exists ( ControlFlowNode arg1 |
14721477 call_to_hasattr ( call , context , use , arg1 ) and
@@ -1580,11 +1585,7 @@ module Conditionals {
15801585 test .getAChild * ( ) = use
15811586 )
15821587 or
1583- exists ( SingleSuccessorGuard unipi |
1584- unipi .getInput ( ) .getASourceUse ( ) = use and
1585- unipi .getTest ( ) = test and
1586- test .getAChild * ( ) = use
1587- )
1588+ any ( SingleSuccessorGuard ssg ) .useAndTest ( use , test )
15881589 }
15891590
15901591 private predicate pinode_test_part ( ControlFlowNode outer , ControlFlowNode inner ) {
@@ -1780,6 +1781,7 @@ cached module Types {
17801781 )
17811782 }
17821783
1784+ pragma [ nomagic]
17831785 private ClassObjectInternal getInheritedMetaclass ( ClassObjectInternal cls ) {
17841786 result = getInheritedMetaclass ( cls , 0 )
17851787 or
@@ -2026,8 +2028,8 @@ module AttributePointsTo {
20262028 variableAttributePointsTo ( def .getInput ( ) , context , name , value , origin )
20272029 }
20282030
2029- private predicate uniEdgedPhiAttributePointsTo ( SingleSuccessorGuard uniphi , PointsToContext context , string name , ObjectInternal value , CfgOrigin origin ) {
2030- variableAttributePointsTo ( uniphi .getInput ( ) , context , name , value , origin )
2031+ private predicate uniEdgedPhiAttributePointsTo ( SingleSuccessorGuard unipi , PointsToContext context , string name , ObjectInternal value , CfgOrigin origin ) {
2032+ variableAttributePointsTo ( unipi .getInput ( ) , context , name , value , origin )
20312033 }
20322034
20332035 private predicate piNodeAttributePointsTo ( PyEdgeRefinement pi , PointsToContext context , string name , ObjectInternal value , CfgOrigin origin ) {
@@ -2108,24 +2110,33 @@ module ModuleAttributes {
21082110 pragma [ nomagic]
21092111 private predicate importStarPointsTo ( ImportStarRefinement def , string name , ObjectInternal value , CfgOrigin origin ) {
21102112 def .getVariable ( ) .isMetaVariable ( ) and
2111- exists ( ImportStarNode imp , ModuleObjectInternal mod |
2112- imp = def . getDefiningNode ( ) and
2113- PointsToInternal :: pointsTo ( imp . getModule ( ) , any ( Context ctx | ctx . isImport ( ) ) , mod , _ )
2114- |
2113+ /* Attribute from imported module */
2114+ exists ( ModuleObjectInternal mod |
2115+ importStarDef ( def , _ , mod )
2116+ and
21152117 /* Attribute from imported module */
21162118 exists ( CfgOrigin orig |
21172119 InterModulePointsTo:: moduleExportsBoolean ( mod , name ) = true and
2118- mod .attribute ( name , value , orig ) and origin = orig .fix ( imp ) and
2119- not exists ( Variable v | v .getId ( ) = name and v .getScope ( ) = imp .getScope ( ) )
2120+ mod .attribute ( name , value , orig ) and origin = orig .fix ( def . getDefiningNode ( ) ) and
2121+ not exists ( Variable v | v .getId ( ) = name and v .getScope ( ) = def .getScope ( ) )
21202122 )
2121- or
2122- /* Retain value held before import */
2123- ( InterModulePointsTo:: moduleExportsBoolean ( mod , name ) = false or name .charAt ( 0 ) = "_" )
2124- and
2123+ )
2124+ or
2125+ /* Retain value held before import */
2126+ exists ( ModuleObjectInternal mod , EssaVariable input |
2127+ importStarDef ( def , input , mod ) and
2128+ ( InterModulePointsTo:: moduleExportsBoolean ( mod , name ) = false or name .charAt ( 0 ) = "_" ) and
21252129 attributePointsTo ( def .getInput ( ) , name , value , origin )
21262130 )
21272131 }
21282132
2133+ private predicate importStarDef ( ImportStarRefinement def , EssaVariable input , ModuleObjectInternal mod ) {
2134+ exists ( ImportStarNode imp |
2135+ def .getVariable ( ) .getName ( ) = "$" and imp = def .getDefiningNode ( ) and
2136+ input = def .getInput ( ) and PointsToInternal:: pointsTo ( imp .getModule ( ) , any ( Context ctx | ctx .isImport ( ) ) , mod , _)
2137+ )
2138+ }
2139+
21292140 /** Points-to for a variable (possibly) redefined by a call:
21302141 * `var = ...; foo(); use(var)`
21312142 * Where var may be redefined in call to `foo` if `var` escapes (is global or non-local).
0 commit comments