Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 23ca403

Browse files
committed
Python points-to: Understand callable and hasattr.
1 parent 8af6cb6 commit 23ca403

1 file changed

Lines changed: 80 additions & 5 deletions

File tree

python/ql/src/semmle/python/pointsto/PointsTo.qll

Lines changed: 80 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -978,7 +978,7 @@ private predicate potential_builtin_points_to(NameNode f, ObjectInternal value,
978978
module 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

Comments
 (0)