Skip to content

Commit f7c6b13

Browse files
authored
Merge pull request github#3640 from RasmusWL/python-handle-3.8-enum-convert
Approved by tausbn
2 parents 5b0d92d + 721713b commit f7c6b13

File tree

4 files changed

+50
-5
lines changed

4 files changed

+50
-5
lines changed

python/ql/src/Variables/UndefinedExport.ql

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,27 @@ predicate mutates_globals(ModuleValue m) {
3333
exists(SubscriptNode sub | sub.getObject() = globals and sub.isStore())
3434
)
3535
or
36-
exists(Value enum_convert, ClassValue enum_class |
36+
// Enum (added in 3.4) has method `_convert_` that alters globals
37+
// This was called `_convert` until 3.8, but that name will be removed in 3.9
38+
exists(ClassValue enum_class |
3739
enum_class.getASuperType() = Value::named("enum.Enum") and
38-
enum_convert = enum_class.attr("_convert") and
39-
exists(CallNode call | call.getScope() = m.getScope() |
40-
enum_convert.getACall() = call or
41-
call.getFunction().pointsTo(enum_convert)
40+
(
41+
// In Python < 3.8, Enum._convert can be found with points-to
42+
exists(Value enum_convert |
43+
enum_convert = enum_class.attr("_convert") and
44+
exists(CallNode call | call.getScope() = m.getScope() |
45+
enum_convert.getACall() = call or
46+
call.getFunction().pointsTo(enum_convert)
47+
)
48+
)
49+
or
50+
// In Python 3.8, Enum._convert_ is implemented using a metaclass, and our points-to
51+
// analysis doesn't handle that well enough. So we need a special case for this
52+
not exists(Value enum_convert | enum_convert = enum_class.attr("_convert")) and
53+
exists(CallNode call | call.getScope() = m.getScope() |
54+
call.getFunction().(AttrNode).getObject(["_convert", "_convert_"]).pointsTo() =
55+
enum_class
56+
)
4257
)
4358
)
4459
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
| test.py:6:5:6:22 | Function Foo.foo | test.py:9:1:9:11 | ControlFlowNode for Attribute() |
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import python
2+
3+
from PythonFunctionValue func
4+
select func, func.getACall()
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Simple classmethod
2+
3+
class Foo(object):
4+
5+
@classmethod
6+
def foo(cls, arg):
7+
print(cls, arg)
8+
9+
Foo.foo(42)
10+
11+
12+
# classmethod defined by metaclass
13+
14+
class BarMeta(type):
15+
16+
def bar(cls, arg):
17+
print(cls, arg)
18+
19+
class Bar(metaclass=BarMeta):
20+
pass
21+
22+
Bar.bar(42) # TODO: No points-to
23+
24+
# If this is solved, please update python/ql/src/Variables/UndefinedExport.ql which has a
25+
# work-around for this behavior

0 commit comments

Comments
 (0)