mirror of
https://github.com/github/codeql.git
synced 2026-04-30 19:26:02 +02:00
Python points-to: Fix up test-evaluate for ABCs and tests involving type().
This commit is contained in:
@@ -53,6 +53,9 @@ class Value extends TObject {
|
||||
result = this.(ObjectInternal).getSource()
|
||||
}
|
||||
|
||||
predicate isBuiltin() {
|
||||
this.(ObjectInternal).isBuiltin()
|
||||
}
|
||||
}
|
||||
|
||||
class ModuleValue extends Value {
|
||||
|
||||
@@ -365,5 +365,15 @@ library class ClassDecl extends @py_object {
|
||||
this instanceof Builtin
|
||||
}
|
||||
|
||||
predicate isAbstractBaseClass(string name) {
|
||||
exists(Module m |
|
||||
m.getName() = "_abcoll"
|
||||
or
|
||||
m.getName() = "_collections_abc"
|
||||
|
|
||||
this.getClass().getScope() = m and
|
||||
this.getName() = name
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -817,24 +817,7 @@ module InterProceduralPointsTo {
|
||||
PointsToInternal::pointsTo(f.getArg(0), context, value, origin)
|
||||
)
|
||||
or
|
||||
value = call_to_type(f, context) and
|
||||
(
|
||||
value.isBuiltin() and origin = f
|
||||
or
|
||||
origin = value.getOrigin()
|
||||
or
|
||||
value = ObjectInternal::unknownClass() and origin = f
|
||||
)
|
||||
}
|
||||
|
||||
pragma [noinline]
|
||||
private ObjectInternal call_to_type(CallNode f, PointsToContext context) {
|
||||
count(f.getArg(_)) = 1 and
|
||||
call(f, context, ObjectInternal::builtin("type")) and
|
||||
exists(ObjectInternal arg |
|
||||
PointsToInternal::pointsTo(f.getArg(0), context, arg, _) and
|
||||
result = arg.getClass()
|
||||
)
|
||||
Expressions::typeCallPointsTo(f, context, value, origin, _, _)
|
||||
}
|
||||
|
||||
/** Points-to for parameter. `def foo(param): ...`. */
|
||||
@@ -1174,6 +1157,16 @@ module Expressions {
|
||||
origin = call
|
||||
}
|
||||
|
||||
pragma [noinline]
|
||||
predicate typeCallPointsTo(CallNode call, PointsToContext context, ObjectInternal value, ControlFlowNode origin, ControlFlowNode arg, ObjectInternal argvalue) {
|
||||
not exists(call.getArg(1)) and
|
||||
arg = call.getArg(0) and
|
||||
InterProceduralPointsTo::call(call, context, ObjectInternal::builtin("type")) and
|
||||
PointsToInternal::pointsTo(arg, context, argvalue, _) and
|
||||
value = argvalue.getClass() and
|
||||
origin = CfgOrigin::fromObject(value).asCfgNodeOrHere(call)
|
||||
}
|
||||
|
||||
pragma [noinline]
|
||||
private predicate lenCallPointsTo(CallNode call, PointsToContext context, ObjectInternal value, ControlFlowNode origin, ControlFlowNode arg, ObjectInternal argvalue) {
|
||||
len_call(call, arg, context, argvalue) and
|
||||
@@ -1317,6 +1310,8 @@ module Expressions {
|
||||
or
|
||||
lenCallPointsTo(expr, context, value, origin, subexpr, subvalue)
|
||||
or
|
||||
typeCallPointsTo(expr, context, value, origin, subexpr, subvalue)
|
||||
or
|
||||
getattrPointsTo(expr, context, value, origin, subexpr, subvalue)
|
||||
or
|
||||
value = ObjectInternal::bool(evaluatesTo(expr, context, subexpr, subvalue)) and origin = expr
|
||||
@@ -1754,7 +1749,9 @@ cached module Types {
|
||||
cached boolean improperSubclass(ObjectInternal sub, ObjectInternal sup) {
|
||||
sub = sup and result = true
|
||||
or
|
||||
result = mroContains(Types::getMro(sub), sup, 0)
|
||||
result = true and mroContains(Types::getMro(sub), sup)
|
||||
or
|
||||
result = false and mroDoesnotContain(Types::getMro(sub), sup, 0)
|
||||
or
|
||||
result = tupleSubclass(sub, sup, 0)
|
||||
}
|
||||
@@ -1768,32 +1765,47 @@ cached module Types {
|
||||
)
|
||||
}
|
||||
|
||||
private boolean mroContains(ClassList mro, ClassObjectInternal sup, int n) {
|
||||
private predicate mroContains(ClassList mro, ClassObjectInternal sup) {
|
||||
mro.contains(sup)
|
||||
or
|
||||
exists(ClassDecl item, ClassDecl sdecl |
|
||||
item = mro.getAnItem().getClassDeclaration() and
|
||||
sdecl = sup.getClassDeclaration() and
|
||||
is_abstract_subclass(item, sdecl)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate mroDoesnotContain(ClassList mro, ClassObjectInternal sup, int n) {
|
||||
exists(ClassObjectInternal cls |
|
||||
Expressions::requireSubClass(cls, sup) and
|
||||
mro = getMro(cls)
|
||||
)
|
||||
and
|
||||
(
|
||||
n = mro.length() and result = false
|
||||
n = mro.length()
|
||||
or
|
||||
mro.getItem(n) = sup and result = true
|
||||
or
|
||||
mro.getItem(n) = abc_to_concrete(sup) and result = true
|
||||
or
|
||||
mro.getItem(n) != sup and sup != AbstractBaseClass::named("Iterable") and
|
||||
mro.getItem(n) != abc_to_concrete(sup) and result = mroContains(mro, sup, n+1)
|
||||
or
|
||||
sup = AbstractBaseClass::named("Iterable") and result = mro.getItem(n).isIterableSubclass()
|
||||
mroDoesnotContain(mro, sup, n+1) and
|
||||
mro.getItem(n) != sup and
|
||||
exists(ClassDecl item, ClassDecl sdecl |
|
||||
item = mro.getItem(n).getClassDeclaration() and
|
||||
sdecl = sup.getClassDeclaration() and
|
||||
not is_abstract_subclass(item, sdecl)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private ClassObjectInternal abc_to_concrete(ClassObjectInternal c) {
|
||||
c = AbstractBaseClass::named("Sequence") and result = ObjectInternal::builtin("list")
|
||||
private predicate is_abstract_subclass(ClassDecl cls, ClassDecl sup) {
|
||||
cls = Builtin::builtin("list") and sup.isAbstractBaseClass("Sequence")
|
||||
or
|
||||
c = AbstractBaseClass::named("Set") and result = ObjectInternal::builtin("set")
|
||||
cls = Builtin::builtin("set") and sup.isAbstractBaseClass("Set")
|
||||
or
|
||||
c = AbstractBaseClass::named("Mapping") and result = ObjectInternal::builtin("dict")
|
||||
cls = Builtin::builtin("dict") and sup.isAbstractBaseClass("Mapping")
|
||||
or
|
||||
cls = Builtin::builtin("list") and sup.isAbstractBaseClass("Iterable")
|
||||
or
|
||||
cls = Builtin::builtin("set") and sup.isAbstractBaseClass("Iterable")
|
||||
or
|
||||
cls = Builtin::builtin("dict") and sup.isAbstractBaseClass("Iterable")
|
||||
}
|
||||
|
||||
cached boolean hasAttr(ObjectInternal cls, string name) {
|
||||
@@ -1822,19 +1834,6 @@ cached module Types {
|
||||
}
|
||||
|
||||
|
||||
module AbstractBaseClass {
|
||||
|
||||
ClassObjectInternal named(string name) {
|
||||
exists(ModuleObjectInternal m |
|
||||
m.getName() = "_abcoll"
|
||||
or
|
||||
m.getName() = "_collections_abc"
|
||||
|
|
||||
m.attribute(name, result, _)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
module AttributePointsTo {
|
||||
|
||||
predicate pointsTo(AttrNode f, Context context, ObjectInternal value, ControlFlowNode origin) {
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
| builtin-class dict | builtin-class dict |
|
||||
| builtin-class dict | builtin-class list |
|
||||
| builtin-class int | (builtin-class float, builtin-class dict) |
|
||||
| builtin-class int | (builtin-class list, builtin-class int) |
|
||||
| builtin-class int | (builtin-class list, builtin-class int) |
|
||||
| builtin-class int | builtin-class dict |
|
||||
| builtin-class int | builtin-class float |
|
||||
| builtin-class int | builtin-class int |
|
||||
| builtin-class int | builtin-class list |
|
||||
| builtin-class int | builtin-class object |
|
||||
| builtin-class int | builtin-class tuple |
|
||||
| builtin-class tuple | builtin-class int |
|
||||
| builtin-class tuple | builtin-class tuple |
|
||||
8
python/ql/test/library-tests/PointsTo/subclass/Checks.ql
Normal file
8
python/ql/test/library-tests/PointsTo/subclass/Checks.ql
Normal file
@@ -0,0 +1,8 @@
|
||||
|
||||
import python
|
||||
import semmle.python.pointsto.PointsTo
|
||||
import semmle.python.pointsto.PointsTo
|
||||
|
||||
from Value sup, Value cls
|
||||
where Expressions::requireSubClass(cls, sup)
|
||||
select cls, sup
|
||||
@@ -0,0 +1,11 @@
|
||||
| 3 | isinstance() | true | x | int 7 |
|
||||
| 4 | issubclass() | true | x | int 7 |
|
||||
| 6 | issubclass() | true | d | builtin-class dict |
|
||||
| 7 | UnaryExpr | true | d | builtin-class dict |
|
||||
| 10 | isinstance() | false | x | int 0 |
|
||||
| 10 | isinstance() | true | x | () |
|
||||
| 13 | isinstance() | false | x | () |
|
||||
| 13 | isinstance() | true | x | int 0 |
|
||||
| 14 | isinstance() | true | x | int 0 |
|
||||
| 15 | issubclass() | true | x | int 0 |
|
||||
| 16 | issubclass() | false | x | int 0 |
|
||||
@@ -0,0 +1,12 @@
|
||||
|
||||
import python
|
||||
import semmle.python.pointsto.PointsTo
|
||||
import semmle.python.objects.ObjectInternal
|
||||
import semmle.python.pointsto.PointsToContext
|
||||
|
||||
|
||||
from ControlFlowNode test, ControlFlowNode use, ObjectInternal val, boolean eval, PointsToContext ctx
|
||||
where
|
||||
PointsTo::pointsTo(use, ctx, val, _) and
|
||||
eval = Conditionals::testEvaluates(test, use, ctx, val, _)
|
||||
select test.getLocation().getStartLine(), test.getNode().toString(), eval.toString(), use.getNode().toString(), val.toString()
|
||||
@@ -0,0 +1,66 @@
|
||||
| 2 | ControlFlowNode for IntegerLiteral | int 7 | 2 |
|
||||
| 3 | ControlFlowNode for int | builtin-class int | 3 |
|
||||
| 3 | ControlFlowNode for isinstance | Builtin-function isinstance | 3 |
|
||||
| 3 | ControlFlowNode for isinstance() | bool True | 3 |
|
||||
| 3 | ControlFlowNode for x | int 7 | 2 |
|
||||
| 4 | ControlFlowNode for issubclass | Builtin-function issubclass | 4 |
|
||||
| 4 | ControlFlowNode for issubclass() | bool True | 4 |
|
||||
| 4 | ControlFlowNode for object | builtin-class object | 4 |
|
||||
| 4 | ControlFlowNode for type | builtin-class type | 4 |
|
||||
| 4 | ControlFlowNode for type() | builtin-class int | 4 |
|
||||
| 4 | ControlFlowNode for x | int 7 | 2 |
|
||||
| 5 | ControlFlowNode for dict | builtin-class dict | 5 |
|
||||
| 6 | ControlFlowNode for d | builtin-class dict | 5 |
|
||||
| 6 | ControlFlowNode for dict | builtin-class dict | 6 |
|
||||
| 6 | ControlFlowNode for issubclass | Builtin-function issubclass | 6 |
|
||||
| 6 | ControlFlowNode for issubclass() | bool True | 6 |
|
||||
| 7 | ControlFlowNode for UnaryExpr | bool True | 7 |
|
||||
| 7 | ControlFlowNode for d | builtin-class dict | 5 |
|
||||
| 7 | ControlFlowNode for issubclass | Builtin-function issubclass | 7 |
|
||||
| 7 | ControlFlowNode for issubclass() | bool False | 7 |
|
||||
| 7 | ControlFlowNode for list | builtin-class list | 7 |
|
||||
| 9 | ControlFlowNode for IfExp | () | 9 |
|
||||
| 9 | ControlFlowNode for IfExp | int 0 | 9 |
|
||||
| 9 | ControlFlowNode for IntegerLiteral | int 0 | 9 |
|
||||
| 9 | ControlFlowNode for Tuple | () | 9 |
|
||||
| 9 | ControlFlowNode for condition | Unknown value | 9 |
|
||||
| 10 | ControlFlowNode for isinstance | Builtin-function isinstance | 10 |
|
||||
| 10 | ControlFlowNode for isinstance() | bool False | 10 |
|
||||
| 10 | ControlFlowNode for isinstance() | bool True | 10 |
|
||||
| 10 | ControlFlowNode for tuple | builtin-class tuple | 10 |
|
||||
| 10 | ControlFlowNode for x | () | 9 |
|
||||
| 10 | ControlFlowNode for x | int 0 | 9 |
|
||||
| 12 | ControlFlowNode for IntegerLiteral | int 3 | 12 |
|
||||
| 12 | ControlFlowNode for isinstance | Builtin-function isinstance | 12 |
|
||||
| 12 | ControlFlowNode for isinstance() | bool False | 12 |
|
||||
| 12 | ControlFlowNode for isinstance() | bool True | 12 |
|
||||
| 12 | ControlFlowNode for unknown | Unknown value | 12 |
|
||||
| 12 | ControlFlowNode for unknown() | Unknown value | 12 |
|
||||
| 13 | ControlFlowNode for int | builtin-class int | 13 |
|
||||
| 13 | ControlFlowNode for isinstance | Builtin-function isinstance | 13 |
|
||||
| 13 | ControlFlowNode for isinstance() | bool False | 13 |
|
||||
| 13 | ControlFlowNode for isinstance() | bool True | 13 |
|
||||
| 13 | ControlFlowNode for x | () | 9 |
|
||||
| 13 | ControlFlowNode for x | int 0 | 9 |
|
||||
| 14 | ControlFlowNode for Tuple | (builtin-class list, builtin-class int) | 14 |
|
||||
| 14 | ControlFlowNode for int | builtin-class int | 14 |
|
||||
| 14 | ControlFlowNode for isinstance | Builtin-function isinstance | 14 |
|
||||
| 14 | ControlFlowNode for isinstance() | bool True | 14 |
|
||||
| 14 | ControlFlowNode for list | builtin-class list | 14 |
|
||||
| 14 | ControlFlowNode for x | int 0 | 9 |
|
||||
| 15 | ControlFlowNode for Tuple | (builtin-class list, builtin-class int) | 15 |
|
||||
| 15 | ControlFlowNode for int | builtin-class int | 15 |
|
||||
| 15 | ControlFlowNode for issubclass | Builtin-function issubclass | 15 |
|
||||
| 15 | ControlFlowNode for issubclass() | bool True | 15 |
|
||||
| 15 | ControlFlowNode for list | builtin-class list | 15 |
|
||||
| 15 | ControlFlowNode for type | builtin-class type | 15 |
|
||||
| 15 | ControlFlowNode for type() | builtin-class int | 15 |
|
||||
| 15 | ControlFlowNode for x | int 0 | 9 |
|
||||
| 16 | ControlFlowNode for Tuple | (builtin-class float, builtin-class dict) | 16 |
|
||||
| 16 | ControlFlowNode for dict | builtin-class dict | 16 |
|
||||
| 16 | ControlFlowNode for float | builtin-class float | 16 |
|
||||
| 16 | ControlFlowNode for issubclass | Builtin-function issubclass | 16 |
|
||||
| 16 | ControlFlowNode for issubclass() | bool False | 16 |
|
||||
| 16 | ControlFlowNode for type | builtin-class type | 16 |
|
||||
| 16 | ControlFlowNode for type() | builtin-class int | 16 |
|
||||
| 16 | ControlFlowNode for x | int 0 | 9 |
|
||||
10
python/ql/test/library-tests/PointsTo/subclass/Values.ql
Normal file
10
python/ql/test/library-tests/PointsTo/subclass/Values.ql
Normal file
@@ -0,0 +1,10 @@
|
||||
|
||||
import python
|
||||
import semmle.python.pointsto.PointsTo
|
||||
import semmle.python.objects.ObjectInternal
|
||||
|
||||
from ControlFlowNode f, ObjectInternal v, ControlFlowNode x
|
||||
|
||||
where PointsTo::pointsTo(f, _, v, x)
|
||||
|
||||
select f.getLocation().getStartLine(), f.toString(), v, x.getLocation().getStartLine()
|
||||
18
python/ql/test/library-tests/PointsTo/subclass/test.py
Normal file
18
python/ql/test/library-tests/PointsTo/subclass/test.py
Normal file
@@ -0,0 +1,18 @@
|
||||
|
||||
x = 7
|
||||
assert isinstance(x, int)
|
||||
assert issubclass(type(x), object)
|
||||
d = dict
|
||||
assert issubclass(d, dict)
|
||||
assert not issubclass(d, list)
|
||||
|
||||
x = 0 if condition else ()
|
||||
if isinstance(x, tuple):
|
||||
pass
|
||||
isinstance(3, unknown())
|
||||
assert isinstance(x, int)
|
||||
assert isinstance(x, (list, int))
|
||||
assert issubclass(type(x), (list, int))
|
||||
if issubclass(type(x), (float, dict)):
|
||||
pass
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
import python
|
||||
import semmle.python.pointsto.PointsTo
|
||||
import semmle.python.pointsto.PointsToContext
|
||||
import semmle.python.objects.ObjectInternal
|
||||
|
||||
from CallNode call, FunctionObject method
|
||||
where PointsTo::Test::super_method_call(_, call, _, method)
|
||||
select call.getLocation().getStartLine(), call.toString(), method.getQualifiedName()
|
||||
|
||||
from CallNode call, SuperInstance sup, BoundMethodObjectInternal bm
|
||||
where call.getFunction().inferredValue() = bm and
|
||||
call.getFunction().(AttrNode).getObject().inferredValue() = sup
|
||||
select call.getLocation().getStartLine(), call.toString(), bm.getFunction().getSource().(FunctionObject).getQualifiedName()
|
||||
@@ -2,8 +2,8 @@
|
||||
import python
|
||||
import semmle.python.pointsto.MRO
|
||||
|
||||
from ClassObject cls
|
||||
from ClassValue cls
|
||||
where not cls.isBuiltin()
|
||||
|
||||
select cls.toString(), new_style_mro(cls)
|
||||
select cls.toString(), Mro::newStyleMro(cls)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user