@@ -319,10 +319,13 @@ cached module PointsToInternal {
319319 pragma [ noinline]
320320 private predicate attribute_load_points_to ( AttrNode f , PointsToContext context , ObjectInternal value , ControlFlowNode origin ) {
321321 f .isLoad ( ) and
322- exists ( ObjectInternal object , string name , CfgOrigin orig |
323- pointsTo ( f .getObject ( name ) , context , object , _) |
324- object .attribute ( name , value , orig ) and
325- origin = orig .fix ( f )
322+ exists ( ObjectInternal object , string name |
323+ pointsTo ( f .getObject ( name ) , context , object , _)
324+ |
325+ exists ( CfgOrigin orig |
326+ object .attribute ( name , value , orig ) and
327+ origin = orig .fix ( f )
328+ )
326329 or
327330 object .attributesUnknown ( ) and
328331 origin = f and value = ObjectInternal:: unknown ( )
@@ -401,7 +404,8 @@ cached module PointsToInternal {
401404 if def .getName ( ) = "__class__" then
402405 exists ( ObjectInternal cls |
403406 pointsTo ( def .getValue ( ) , context , cls , _) and
404- value = TUnknownInstance ( cls )
407+ value = TUnknownInstance ( cls ) and
408+ origin = CfgOrigin:: fromCfgNode ( def .getDefiningNode ( ) )
405409 )
406410 else
407411 variablePointsTo ( def .getInput ( ) , context , value , origin )
@@ -419,9 +423,10 @@ cached module PointsToInternal {
419423
420424 /** Holds if ESSA edge refinement, `def`, refers to `(value, cls, origin)`. */
421425 private predicate ssa_filter_definition_points_to ( PyEdgeRefinement def , PointsToContext context , ObjectInternal value , CfgOrigin origin ) {
422- exists ( ControlFlowNode test , ControlFlowNode use |
423- refinement_test ( test , use , Conditionals:: branchEvaluatesTo ( test , use , context , value , origin .toCfgNode ( ) ) , def )
424- )
426+ def .getSense ( ) = Conditionals:: testEvaluates ( def .getTest ( ) , def .getInput ( ) .getASourceUse ( ) , context , value , origin )
427+ //exists(ControlFlowNode test, ControlFlowNode use |
428+ // refinement_test(test, use, Conditionals::branchEvaluatesTo(test, use, context, value, origin.toCfgNode()), def)
429+ //)
425430 }
426431
427432 /** Holds if ESSA definition, `uniphi`, refers to `(value, origin)`. */
@@ -431,9 +436,9 @@ cached module PointsToInternal {
431436 /* Because calls such as `len` may create a new variable, we need to go via the source variable
432437 * That is perfectly safe as we are only dealing with calls that do not mutate their arguments.
433438 */
434- use = uniphi .getInput ( ) .getSourceVariable ( ) . ( Variable ) . getAUse ( ) and
435- test = uniphi .getDefiningNode ( ) and
436- uniphi .getSense ( ) = Conditionals:: branchEvaluatesTo ( test , use , context , value , origin .toCfgNode ( ) )
439+ use = uniphi .getInput ( ) .getASourceUse ( ) and
440+ test = uniphi .getTest ( ) and
441+ uniphi .getSense ( ) = Conditionals:: testEvaluates ( test , use , context , value , origin .toCfgNode ( ) )
437442 )
438443 }
439444
@@ -535,7 +540,10 @@ cached module PointsToInternal {
535540
536541 pragma [ noinline]
537542 private predicate test_expr_points_to ( ControlFlowNode cmp , PointsToContext context , ObjectInternal value ) {
538- value = ObjectInternal:: bool ( Conditionals:: testEvaluatesTo ( cmp , _, context , _, _) )
543+ exists ( ControlFlowNode use |
544+ value = Conditionals:: evaluates ( cmp , use , context , _, _) and
545+ use != cmp
546+ )
539547 // or
540548 // value = version_tuple_compare(cmp, context)
541549 }
@@ -969,80 +977,110 @@ private predicate potential_builtin_points_to(NameNode f, ObjectInternal value,
969977
970978module Conditionals {
971979
972- /** Holds if `expr` is the operand of a unary `not` expression. */
973- private ControlFlowNode not_operand ( ControlFlowNode expr ) {
974- expr .( UnaryExprNode ) .getNode ( ) .getOp ( ) instanceof Not and
975- result = expr .( UnaryExprNode ) .getOperand ( )
980+ boolean testEvaluates ( ControlFlowNode expr , ControlFlowNode use , PointsToContext context , ObjectInternal value , ControlFlowNode origin ) {
981+ //pinode_test(expr, use) and
982+ result = evaluates ( expr , use , context , value , origin ) .booleanValue ( )
976983 }
977984
978- boolean branchEvaluatesTo ( ControlFlowNode expr , ControlFlowNode use , PointsToContext context , ObjectInternal val , ControlFlowNode origin ) {
979- contains_interesting_expression_within_test ( expr , use ) and
985+ ObjectInternal evaluates ( ControlFlowNode expr , ControlFlowNode use , PointsToContext context , ObjectInternal val , ControlFlowNode origin ) {
980986 PointsToInternal:: pointsTo ( use , context , val , origin ) and
981- (
982- expr = use and
983- val .booleanValue ( ) = result
987+ pinode_test ( _, use ) and expr = use and result = val
988+ or
989+ exists ( ControlFlowNode part , ObjectInternal partval |
990+ pinode_test_part ( expr , part ) and
991+ partval = evaluates ( part , use , context , val , origin )
992+ |
993+ result = equalityEvaluates ( expr , part , context , partval )
984994 or
985- exists ( string name , ObjectInternal attr |
986- expr .( AttrNode ) .getObject ( name ) = use |
987- val .attribute ( name , attr , _) and
988- result = attr .booleanValue ( )
995+ result = ObjectInternal:: bool ( inequalityEvaluatesBoolean ( expr , part , context , partval ) )
996+ or
997+ result = ObjectInternal:: bool ( isinstance_test_evaluates_boolean ( expr , part , context , partval ) )
998+ or
999+ result = ObjectInternal:: bool ( issubclass_test_evaluates_boolean ( expr , part , context , partval ) )
1000+ or
1001+ exists ( string attr |
1002+ expr .( AttrNode ) .getObject ( attr ) = use |
1003+ val .attribute ( attr , result , _)
9891004 or
990- val .attributesUnknown ( ) and
991- result = maybe ( )
1005+ val .attributesUnknown ( ) and result = ObjectInternal:: unknown ( )
9921006 )
1007+ or
1008+ expr instanceof BinaryExprNode and result = ObjectInternal:: unknown ( )
1009+ or
1010+ part = not_operand ( expr ) and result = ObjectInternal:: bool ( partval .booleanValue ( ) .booleanNot ( ) )
1011+ or
1012+ result = evaluatesLen ( expr , part , context , partval )
1013+ //or
1014+ //result = callable_test_evaluates_boolean(expr, use, context, val, origin)
1015+ //or
1016+ //result = hasattr_test_evaluates_boolean(expr, use, context, val, origin)
9931017 )
994- or
995- result = testEvaluatesTo ( expr , use , context , val , origin )
996- or
997- result = branchEvaluatesTo ( not_operand ( expr ) , use , context , val , origin ) .booleanNot ( )
1018+
9981019 }
9991020
1000- boolean testEvaluatesTo ( ControlFlowNode expr , ControlFlowNode use , PointsToContext context , ObjectInternal val , ControlFlowNode origin ) {
1001- result = equalityEvaluatesTo ( expr , use , context , val , origin )
1002- or
1003- result = inequalityEvaluatesTo ( expr , use , context , val , origin )
1004- or
1005- result = isinstance_test_evaluates_boolean ( expr , use , context , val , origin )
1006- or
1007- result = issubclass_test_evaluates_boolean ( expr , use , context , val , origin )
1008- //or
1009- //result = callable_test_evaluates_boolean(expr, use, context, val, origin)
1010- //or
1011- //result = hasattr_test_evaluates_boolean(expr, use, context, val, origin)
1021+ /** Holds if `expr` is the operand of a unary `not` expression. */
1022+ private ControlFlowNode not_operand ( ControlFlowNode expr ) {
1023+ expr .( UnaryExprNode ) .getNode ( ) .getOp ( ) instanceof Not and
1024+ result = expr .( UnaryExprNode ) .getOperand ( )
10121025 }
10131026
10141027 pragma [ noinline]
1015- private boolean equalityEvaluatesTo ( ControlFlowNode expr , ControlFlowNode use , PointsToContext context , ObjectInternal val , ControlFlowNode origin ) {
1028+ private ObjectInternal equalityEvaluates ( ControlFlowNode expr , ControlFlowNode use , PointsToContext context , ObjectInternal val ) {
10161029 exists ( ControlFlowNode r , boolean sense |
1017- equality_test ( expr , use , sense , r ) and
1030+ pinode_test_part ( expr , use ) and equality_test ( expr , use , sense , r ) and
10181031 exists ( ObjectInternal other |
1019- PointsToInternal:: pointsTo ( use , context , val , origin ) and
1032+ PointsToInternal:: pointsTo ( use , context , val , _ ) and
10201033 PointsToInternal:: pointsTo ( r , context , other , _) |
10211034 val .isComparable ( ) = true and other .isComparable ( ) = true and
10221035 (
1023- other = val and result = sense
1036+ other = val and result = ObjectInternal :: bool ( sense )
10241037 or
1025- other != val and result = sense .booleanNot ( )
1038+ other != val and result = ObjectInternal :: bool ( sense .booleanNot ( ) )
10261039 )
10271040 or
1028- val .isComparable ( ) = false and result = maybe ( )
1041+ val .isComparable ( ) = false and result = ObjectInternal :: bool ( _ )
10291042 or
1030- other .isComparable ( ) = false and result = maybe ( )
1043+ other .isComparable ( ) = false and result = ObjectInternal :: bool ( _ )
10311044 )
10321045 )
10331046 }
10341047
1035- private predicate isinstance_call ( CallNode call , ControlFlowNode use , PointsToContext context , ObjectInternal val , ObjectInternal cls , ControlFlowNode origin ) {
1048+ /** Holds if `c` is a test comparing `x` and `y`. `is` is true if the operator is `is` or `==`, it is false if the operator is `is not` or `!=`. */
1049+ private predicate equality_test ( CompareNode c , ControlFlowNode x , boolean is , ControlFlowNode y ) {
1050+ exists ( Cmpop op |
1051+ c .operands ( x , op , y ) or
1052+ c .operands ( y , op , x )
1053+ |
1054+ ( is = true and op instanceof Is or
1055+ is = false and op instanceof IsNot or
1056+ is = true and op instanceof Eq or
1057+ is = false and op instanceof NotEq
1058+ )
1059+ )
1060+ }
1061+
1062+ pragma [ noinline]
1063+ private ObjectInternal evaluatesLen ( CallNode call , ControlFlowNode use , PointsToContext context , ObjectInternal val ) {
1064+ pinode_test_part ( call , use ) and
1065+ PointsToInternal:: pointsTo ( use , context , val , _) and
1066+ PointsToInternal:: pointsTo ( call .getFunction ( ) , context , ObjectInternal:: builtin ( "len" ) , _) and
1067+ result = TInt ( val .( SequenceObjectInternal ) .length ( ) )
1068+ }
1069+
1070+ //private
1071+ predicate isinstance_call ( CallNode call , ControlFlowNode use , PointsToContext context , ObjectInternal val , ObjectInternal cls , ControlFlowNode origin ) {
1072+ pinode_test_part ( call , use ) and
10361073 PointsToInternal:: pointsTo ( call .getFunction ( ) , context , ObjectInternal:: builtin ( "isinstance" ) , _) and
10371074 use = call .getArg ( 0 ) and
10381075 PointsToInternal:: pointsTo ( use , context , val , origin ) and
10391076 PointsToInternal:: pointsTo ( call .getArg ( 1 ) , context , cls , _)
10401077 }
10411078
10421079 pragma [ nomagic]
1043- private boolean isinstance_test_evaluates_boolean ( CallNode call , ControlFlowNode use , PointsToContext context , ObjectInternal val , ControlFlowNode origin ) {
1080+ //private
1081+ boolean isinstance_test_evaluates_boolean ( CallNode call , ControlFlowNode use , PointsToContext context , ObjectInternal val ) {
10441082 exists ( ObjectInternal cls |
1045- isinstance_call ( call , use , context , val , cls , origin ) |
1083+ isinstance_call ( call , use , context , val , cls , _ ) |
10461084 result = Types:: improperSubclass ( val .getClass ( ) , cls )
10471085 or
10481086 val = ObjectInternal:: unknown ( ) and result = maybe ( )
@@ -1061,9 +1099,10 @@ module Conditionals {
10611099 }
10621100
10631101 pragma [ nomagic]
1064- private boolean issubclass_test_evaluates_boolean ( CallNode call , ControlFlowNode use , PointsToContext context , ObjectInternal val , ControlFlowNode origin ) {
1102+ private boolean issubclass_test_evaluates_boolean ( CallNode call , ControlFlowNode use , PointsToContext context , ObjectInternal val ) {
1103+ pinode_test_part ( call , use ) and
10651104 exists ( ObjectInternal cls |
1066- issubclass_call ( call , use , context , val , cls , origin ) |
1105+ issubclass_call ( call , use , context , val , cls , _ ) |
10671106 result = Types:: improperSubclass ( val , cls )
10681107 or
10691108 val = ObjectInternal:: unknownClass ( ) and result = maybe ( )
@@ -1091,15 +1130,16 @@ module Conditionals {
10911130 }
10921131
10931132 pragma [ noinline]
1094- private boolean inequalityEvaluatesTo ( ControlFlowNode expr , ControlFlowNode use , PointsToContext context , ObjectInternal val , ControlFlowNode origin ) {
1133+ private boolean inequalityEvaluatesBoolean ( ControlFlowNode expr , ControlFlowNode use , PointsToContext context , ObjectInternal val ) {
1134+ pinode_test_part ( expr , use ) and
10951135 exists ( ControlFlowNode r , boolean sense |
10961136 exists ( boolean strict , ObjectInternal other |
10971137 (
10981138 inequality ( expr , use , r , strict ) and sense = true
10991139 or
11001140 inequality ( expr , r , use , strict ) and sense = false
11011141 ) and
1102- PointsToInternal:: pointsTo ( use , context , val , origin ) and
1142+ PointsToInternal:: pointsTo ( use , context , val , _ ) and
11031143 PointsToInternal:: pointsTo ( r , context , other , _)
11041144 |
11051145 val .intValue ( ) < other .intValue ( ) and result = sense
@@ -1135,6 +1175,29 @@ module Conditionals {
11351175 )
11361176 }
11371177
1178+ private predicate pinode_test ( ControlFlowNode test , NameNode use ) {
1179+ exists ( PyEdgeRefinement pi |
1180+ pi .getInput ( ) .getASourceUse ( ) = use and
1181+ pi .getTest ( ) = test and
1182+ test .getAChild * ( ) = use
1183+ )
1184+ or
1185+ exists ( SingleSuccessorGuard unipi |
1186+ unipi .getInput ( ) .getASourceUse ( ) = use and
1187+ unipi .getTest ( ) = test and
1188+ test .getAChild * ( ) = use
1189+ )
1190+ }
1191+
1192+ private predicate pinode_test_part ( ControlFlowNode outer , ControlFlowNode inner ) {
1193+ exists ( ControlFlowNode test , NameNode use |
1194+ pinode_test ( test , use ) and
1195+ test .getAChild * ( ) = outer and
1196+ outer .getAChild + ( ) = inner and
1197+ inner .getAChild * ( ) = use
1198+ )
1199+ }
1200+
11381201}
11391202
11401203cached module Types {
0 commit comments