Skip to content

Commit b973806

Browse files
try excluding set methods, add methods, update alert messages
1 parent 73d257e commit b973806

File tree

1 file changed

+29
-26
lines changed

1 file changed

+29
-26
lines changed

python/ql/src/Functions/IncorrectRaiseInSpecialMethod.ql

Lines changed: 29 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,16 @@ import semmle.python.ApiGraphs
1616
import semmle.python.dataflow.new.internal.DataFlowDispatch
1717

1818
private predicate attributeMethod(string name) {
19-
name = "__getattribute__" or name = "__getattr__" or name = "__setattr__"
19+
name = ["__getattribute__", "__getattr__"] // __setattr__ excluded as it makes sense to raise different kinds of errors based on the `value` parameter
2020
}
2121

2222
private predicate indexingMethod(string name) {
23-
name = "__getitem__" or name = "__setitem__" or name = "__delitem__"
23+
name = ["__getitem__", "__delitem__"] // __setitem__ excluded as it makes sense to raise different kinds of errors based on the `value` parameter
2424
}
2525

2626
private predicate arithmeticMethod(string name) {
27-
name in [
27+
name =
28+
[
2829
"__add__", "__sub__", "__or__", "__xor__", "__rshift__", "__pow__", "__mul__", "__neg__",
2930
"__radd__", "__rsub__", "__rdiv__", "__rfloordiv__", "__div__", "__rdiv__", "__rlshift__",
3031
"__rand__", "__ror__", "__rxor__", "__rrshift__", "__rpow__", "__rmul__", "__truediv__",
@@ -35,32 +36,32 @@ private predicate arithmeticMethod(string name) {
3536
}
3637

3738
private predicate orderingMethod(string name) {
38-
name = "__lt__"
39-
or
40-
name = "__le__"
41-
or
42-
name = "__gt__"
43-
or
44-
name = "__ge__"
39+
name =
40+
[
41+
"__lt__",
42+
"__le__",
43+
"__gt__",
44+
"__ge__",
45+
]
4546
}
4647

4748
private predicate castMethod(string name) {
48-
name = "__int__"
49-
or
50-
name = "__float__"
51-
or
52-
name = "__long__"
53-
or
54-
name = "__trunc__"
55-
or
56-
name = "__complex__"
49+
name =
50+
[
51+
"__int__",
52+
"__float__",
53+
"__long__",
54+
"__trunc__",
55+
"__complex__"
56+
]
5757
}
5858

5959
predicate correctRaise(string name, Expr exec) {
6060
execIsOfType(exec, "TypeError") and
6161
(
6262
indexingMethod(name) or
63-
attributeMethod(name)
63+
attributeMethod(name) or
64+
name = ["__add__", "__iadd__", "__radd__"]
6465
)
6566
or
6667
exists(string execName |
@@ -81,11 +82,11 @@ predicate preferredRaise(string name, string execName, string message) {
8182
or
8283
orderingMethod(name) and
8384
execName = "TypeError" and
84-
message = "should raise a TypeError, or return NotImplemented instead."
85+
message = "should raise a TypeError or return NotImplemented instead."
8586
or
8687
arithmeticMethod(name) and
8788
execName = "ArithmeticError" and
88-
message = "should raise an ArithmeticError, or return NotImplemented instead."
89+
message = "should raise an ArithmeticError or return NotImplemented instead."
8990
or
9091
name = "__bool__" and
9192
execName = "TypeError" and
@@ -120,6 +121,7 @@ predicate noNeedToAlwaysRaise(Function meth, string message, boolean allowNotImp
120121
castMethod(meth.getName()) and
121122
message = "this method does not need to be implemented." and
122123
allowNotImplemented = true and
124+
// Allow an always raising cast method if it's overriding other behavior
123125
not exists(Function overridden |
124126
overridden.getName() = meth.getName() and
125127
overridden.getScope() = getADirectSuperclass+(meth.getScope()) and
@@ -139,7 +141,7 @@ predicate directlyRaises(Function f, Expr exec) {
139141
exists(Raise r |
140142
r.getScope() = f and
141143
exec = r.getException() and
142-
not exec = API::builtin("StopIteration").asSource().asExpr()
144+
exec instanceof Call
143145
)
144146
}
145147

@@ -156,15 +158,16 @@ where
156158
exists(boolean allowNotImplemented, string subMessage |
157159
alwaysRaises(f, exec) and
158160
noNeedToAlwaysRaise(f, subMessage, allowNotImplemented) and
159-
(allowNotImplemented = false or not isNotImplementedError(exec)) and
161+
(allowNotImplemented = true implies not isNotImplementedError(exec)) and // don't alert if it's a NotImplementedError and that's ok
160162
message = "This method always raises $@ - " + subMessage
161163
)
162164
or
163-
alwaysRaises(f, exec) and // for now consider only alwaysRaises cases as original query
164165
not isNotImplementedError(exec) and
165166
not correctRaise(f.getName(), exec) and
166167
exists(string subMessage | preferredRaise(f.getName(), _, subMessage) |
167-
message = "This method always raises $@ - " + subMessage
168+
if alwaysRaises(f, exec)
169+
then message = "This method always raises $@ - " + subMessage
170+
else message = "This method raises $@ - " + subMessage
168171
)
169172
)
170173
select f, message, exec, exec.toString() // TODO: remove tostring

0 commit comments

Comments
 (0)