Skip to content

Commit e6b27b3

Browse files
committed
Python: Update incorrect comparison queries to use new API. WORK IN PROGRESS.
1 parent cb719a8 commit e6b27b3

File tree

3 files changed

+24
-18
lines changed

3 files changed

+24
-18
lines changed

python/ql/src/Expressions/IncorrectComparisonUsingIs.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
import python
1414
import IsComparisons
1515

16-
from Compare comp, Cmpop op, ClassObject c, string alt
16+
from Compare comp, Cmpop op, ClassValue c, string alt
1717
where invalid_portable_is_comparison(comp, op, c) and
1818
not cpython_interned_constant(comp.getASubExpression()) and
1919
(op instanceof Is and alt = "==" or op instanceof IsNot and alt = "!=")

python/ql/src/Expressions/IsComparisons.qll

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,25 +7,31 @@ predicate comparison_using_is(Compare comp, ControlFlowNode left, Cmpop op, Cont
77
)
88
}
99

10-
predicate overrides_eq_or_cmp(ClassObject c) {
10+
predicate overrides_eq_or_cmp(ClassValue c) {
1111
major_version() = 2 and c.hasAttribute("__eq__")
1212
or
13-
c.declaresAttribute("__eq__") and not c = theObjectType()
13+
c.declaresAttribute("__eq__") and not c = Value::named("object")
1414
or
15-
exists(ClassObject sup |
16-
sup = c.getASuperType() and not sup = theObjectType() |
15+
exists(ClassValue sup |
16+
sup = c.getASuperType() and not sup = Value::named("object") |
1717
sup.declaresAttribute("__eq__")
1818
)
1919
or
2020
major_version() = 2 and c.hasAttribute("__cmp__")
2121
}
2222

23-
predicate invalid_to_use_is_portably(ClassObject c) {
23+
predicate probablySingleton(ClassValue cls) {
24+
strictcount(Value inst | inst.getClass() = cls) = 1
25+
or
26+
cls = Value::named("None").getClass()
27+
}
28+
29+
predicate invalid_to_use_is_portably(ClassValue c) {
2430
overrides_eq_or_cmp(c) and
2531
/* Exclude type/builtin-function/bool as it is legitimate to compare them using 'is' but they implement __eq__ */
26-
not c = theTypeType() and not c = theBuiltinFunctionType() and not c = theBoolType() and
32+
not c = Value::named("type") and not c = ClassValue::builtinFunction() and not c = Value::named("bool") and
2733
/* OK to compare with 'is' if a singleton */
28-
not exists(c.getProbableSingletonInstance())
34+
not probablySingleton(c)
2935
}
3036

3137
predicate simple_constant(ControlFlowNode f) {
@@ -72,30 +78,30 @@ predicate universally_interned_constant(Expr e) {
7278
)
7379
}
7480

75-
private predicate comparison_both_types(Compare comp, Cmpop op, ClassObject cls1, ClassObject cls2) {
81+
private predicate comparison_both_types(Compare comp, Cmpop op, ClassValue cls1, ClassValue cls2) {
7682
exists(ControlFlowNode op1, ControlFlowNode op2 |
7783
comparison_using_is(comp, op1, op, op2) or comparison_using_is(comp, op2, op, op1) |
78-
op1.refersTo(_, cls1, _) and
79-
op2.refersTo(_, cls2, _)
84+
op1.inferredValue().getClass() = cls1 and
85+
op2.inferredValue().getClass() = cls2
8086
)
8187
}
8288

83-
private predicate comparison_one_type(Compare comp, Cmpop op, ClassObject cls) {
89+
private predicate comparison_one_type(Compare comp, Cmpop op, ClassValue cls) {
8490
not comparison_both_types(comp, _, _, _) and
8591
exists(ControlFlowNode operand |
8692
comparison_using_is(comp, operand, op, _) or comparison_using_is(comp, _, op, operand) |
87-
operand.refersTo(_, cls, _)
93+
operand.inferredValue().getClass() = cls
8894
)
8995
}
9096

91-
predicate invalid_portable_is_comparison(Compare comp, Cmpop op, ClassObject cls) {
97+
predicate invalid_portable_is_comparison(Compare comp, Cmpop op, ClassValue cls) {
9298
/* OK to use 'is' when defining '__eq__' */
9399
not exists(Function eq | eq.getName() = "__eq__" or eq.getName() = "__ne__" | eq = comp.getScope().getScope*())
94100
and
95101
(
96102
comparison_one_type(comp, op, cls) and invalid_to_use_is_portably(cls)
97103
or
98-
exists(ClassObject other | comparison_both_types(comp, op, cls, other) |
104+
exists(ClassValue other | comparison_both_types(comp, op, cls, other) |
99105
invalid_to_use_is_portably(cls) and
100106
invalid_to_use_is_portably(other)
101107
)
@@ -123,9 +129,9 @@ predicate invalid_portable_is_comparison(Compare comp, Cmpop op, ClassObject cls
123129
}
124130

125131
private predicate enum_member(AstNode obj) {
126-
exists(ClassObject cls, AssignStmt asgn |
132+
exists(ClassValue cls, AssignStmt asgn |
127133
cls.getASuperType().getName() = "Enum" |
128-
cls.getPyClass() = asgn.getScope() and
134+
cls.getScope() = asgn.getScope() and
129135
asgn.getValue() = obj
130136
)
131137
}

python/ql/src/Expressions/NonPortableComparisonUsingIs.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
import python
1414
import IsComparisons
1515

16-
from Compare comp, Cmpop op, ClassObject c
16+
from Compare comp, Cmpop op, ClassValue c
1717
where invalid_portable_is_comparison(comp, op, c) and
1818
exists(Expr sub |
1919
sub = comp.getASubExpression() |

0 commit comments

Comments
 (0)