@@ -978,7 +978,7 @@ private predicate potential_builtin_points_to(NameNode f, ObjectInternal value,
978978module Conditionals {
979979
980980 boolean testEvaluates ( ControlFlowNode expr , ControlFlowNode use , PointsToContext context , ObjectInternal value , ControlFlowNode origin ) {
981- // pinode_test(expr, use) and
981+ pinode_test ( expr , use ) and
982982 result = evaluates ( expr , use , context , value , origin ) .booleanValue ( )
983983 }
984984
@@ -1010,10 +1010,10 @@ module Conditionals {
10101010 part = not_operand ( expr ) and result = ObjectInternal:: bool ( partval .booleanValue ( ) .booleanNot ( ) )
10111011 or
10121012 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 )
1013+ or
1014+ result = callable_test_evaluates ( expr , part , context , partval )
1015+ or
1016+ result = hasattr_test_evaluates ( expr , part , context , partval )
10171017 )
10181018
10191019 }
@@ -1067,6 +1067,49 @@ module Conditionals {
10671067 result = TInt ( val .( SequenceObjectInternal ) .length ( ) )
10681068 }
10691069
1070+ pragma [ noinline]
1071+ private ObjectInternal callable_test_evaluates ( CallNode call , ControlFlowNode use , PointsToContext context , ObjectInternal val ) {
1072+ callable_call ( call , use , context , val ) and
1073+ (
1074+ val = ObjectInternal:: unknown ( ) and result = ObjectInternal:: bool ( _)
1075+ or
1076+ val = ObjectInternal:: unknownClass ( ) and result = ObjectInternal:: bool ( _)
1077+ or
1078+ result = ObjectInternal:: bool ( Types:: hasAttr ( val .getClass ( ) , "__call__" ) )
1079+ )
1080+ }
1081+
1082+ pragma [ noinline]
1083+ private ObjectInternal hasattr_test_evaluates ( CallNode call , ControlFlowNode use , PointsToContext context , ObjectInternal val ) {
1084+ exists ( string name |
1085+ hasattr_call ( call , use , context , val , name )
1086+ |
1087+ val = ObjectInternal:: unknown ( ) and result = ObjectInternal:: bool ( _)
1088+ or
1089+ val = ObjectInternal:: unknownClass ( ) and result = ObjectInternal:: bool ( _)
1090+ or
1091+ result = ObjectInternal:: bool ( Types:: hasAttr ( val .getClass ( ) , name ) )
1092+ )
1093+ }
1094+
1095+ private predicate callable_call ( CallNode call , ControlFlowNode use , PointsToContext context , ObjectInternal val ) {
1096+ pinode_test_part ( call , use ) and
1097+ PointsToInternal:: pointsTo ( call .getFunction ( ) , context , ObjectInternal:: builtin ( "callable" ) , _) and
1098+ use = call .getArg ( 0 ) and
1099+ PointsToInternal:: pointsTo ( use , context , val , _)
1100+ }
1101+
1102+ private predicate hasattr_call ( CallNode call , ControlFlowNode use , PointsToContext context , ObjectInternal val , string name ) {
1103+ pinode_test_part ( call , use ) and
1104+ PointsToInternal:: pointsTo ( call .getFunction ( ) , context , ObjectInternal:: builtin ( "hasattr" ) , _) and
1105+ use = call .getArg ( 0 ) and
1106+ PointsToInternal:: pointsTo ( use , context , val , _) and
1107+ exists ( StringObjectInternal str |
1108+ PointsToInternal:: pointsTo ( call .getArg ( 1 ) , context , str , _) and
1109+ str .strValue ( ) = name
1110+ )
1111+ }
1112+
10701113 //private
10711114 predicate isinstance_call ( CallNode call , ControlFlowNode use , PointsToContext context , ObjectInternal val , ObjectInternal cls , ControlFlowNode origin ) {
10721115 pinode_test_part ( call , use ) and
@@ -1129,6 +1172,16 @@ module Conditionals {
11291172 )
11301173 }
11311174
1175+ predicate requireHasAttr ( ClassObjectInternal cls , string name ) {
1176+ cls != ObjectInternal:: unknownClass ( ) and
1177+ exists ( ObjectInternal val |
1178+ val .getClass ( ) = cls |
1179+ name = "__call__" and callable_call ( _, _, _, val )
1180+ or
1181+ hasattr_call ( _, _, _, val , name )
1182+ )
1183+ }
1184+
11321185 pragma [ noinline]
11331186 private boolean inequalityEvaluatesBoolean ( ControlFlowNode expr , ControlFlowNode use , PointsToContext context , ObjectInternal val ) {
11341187 pinode_test_part ( expr , use ) and
@@ -1433,5 +1486,27 @@ cached module Types {
14331486 )
14341487 }
14351488
1489+ cached boolean hasAttr ( ObjectInternal cls , string name ) {
1490+ result = mroHasAttr ( Types:: getMro ( cls ) , name , 0 )
1491+ }
1492+
1493+ private boolean mroHasAttr ( ClassList mro , string name , int n ) {
1494+ exists ( ClassObjectInternal cls |
1495+ Conditionals:: requireHasAttr ( cls , name ) and
1496+ mro = getMro ( cls )
1497+ )
1498+ and
1499+ (
1500+ n = mro .length ( ) and result = false
1501+ or
1502+ exists ( ClassDecl decl |
1503+ decl = mro .getItem ( n ) .getClassDeclaration ( ) |
1504+ if decl .declaresAttribute ( name ) then
1505+ result = true
1506+ else
1507+ result = mroHasAttr ( mro , name , n + 1 )
1508+ )
1509+ )
1510+ }
14361511
14371512}
0 commit comments