mirror of
https://github.com/github/codeql.git
synced 2025-12-16 16:53:25 +01:00
Update unit tests
This commit is contained in:
@@ -7,7 +7,7 @@
|
||||
* error-handling
|
||||
* @problem.severity recommendation
|
||||
* @sub-severity high
|
||||
* @precision very-high
|
||||
* @precision high
|
||||
* @id py/unexpected-raise-in-special-method
|
||||
*/
|
||||
|
||||
@@ -16,7 +16,7 @@ import semmle.python.ApiGraphs
|
||||
import semmle.python.dataflow.new.internal.DataFlowDispatch
|
||||
|
||||
private predicate attributeMethod(string name) {
|
||||
name = ["__getattribute__", "__getattr__"] // __setattr__ excluded as it makes sense to raise different kinds of errors based on the `value` parameter
|
||||
name = ["__getattribute__", "__getattr__", "__delattr__"] // __setattr__ excluded as it makes sense to raise different kinds of errors based on the `value` parameter
|
||||
}
|
||||
|
||||
private predicate indexingMethod(string name) {
|
||||
@@ -50,7 +50,7 @@ private predicate castMethod(string name) {
|
||||
[
|
||||
"__int__",
|
||||
"__float__",
|
||||
"__long__",
|
||||
"__index__",
|
||||
"__trunc__",
|
||||
"__complex__"
|
||||
]
|
||||
@@ -61,6 +61,7 @@ predicate correctRaise(string name, Expr exec) {
|
||||
(
|
||||
indexingMethod(name) or
|
||||
attributeMethod(name) or
|
||||
// Allow add methods to raise a TypeError, as they can be used for sequence concatenation as well as arithmetic
|
||||
name = ["__add__", "__iadd__", "__radd__"]
|
||||
)
|
||||
or
|
||||
@@ -125,7 +126,7 @@ predicate noNeedToAlwaysRaise(Function meth, string message, boolean allowNotImp
|
||||
not exists(Function overridden |
|
||||
overridden.getName() = meth.getName() and
|
||||
overridden.getScope() = getADirectSuperclass+(meth.getScope()) and
|
||||
alwaysRaises(overridden, _)
|
||||
not alwaysRaises(overridden, _)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
| test.py:6:5:6:33 | Function __getitem__ | This method always raises $@ - should raise a LookupError (KeyError or IndexError) instead. | test.py:7:15:7:33 | ZeroDivisionError() | ZeroDivisionError |
|
||||
| test.py:9:5:9:32 | Function __getattr__ | This method always raises $@ - should raise an AttributeError instead. | test.py:10:15:10:33 | ZeroDivisionError() | ZeroDivisionError |
|
||||
| test.py:12:5:12:23 | Function __bool__ | This method always raises $@ - should raise a TypeError instead. | test.py:13:15:13:26 | ValueError() | ValueError |
|
||||
| test.py:15:5:15:22 | Function __int__ | This method always raises $@ - this method does not need to be implemented. | test.py:16:15:16:26 | ValueError() | ValueError |
|
||||
| test.py:24:5:24:23 | Function __hash__ | This method always raises $@ - use __hash__ = None instead. | test.py:25:15:25:35 | NotImplementedError() | NotImplementedError |
|
||||
| test.py:28:5:28:29 | Function __sub__ | This method raises $@ - should raise an ArithmeticError or return NotImplemented instead. | test.py:30:19:30:29 | TypeError() | TypeError |
|
||||
@@ -0,0 +1,2 @@
|
||||
query: Functions/IncorrectRaiseInSpecialMethod.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
@@ -0,0 +1,66 @@
|
||||
class A:
|
||||
|
||||
def __add__(self, other): # No alert - Always allow NotImplementedError
|
||||
raise NotImplementedError()
|
||||
|
||||
def __getitem__(self, index): # $ Alert
|
||||
raise ZeroDivisionError()
|
||||
|
||||
def __getattr__(self, name): # $ Alert
|
||||
raise ZeroDivisionError()
|
||||
|
||||
def __bool__(self): # $ Alert
|
||||
raise ValueError()
|
||||
|
||||
def __int__(self): # $ Alert # Cast method need not be defined to always raise
|
||||
raise ValueError()
|
||||
|
||||
def __float__(self): # No alert - OK to raise conditionally
|
||||
if self.z:
|
||||
return 0
|
||||
else:
|
||||
raise ValueError()
|
||||
|
||||
def __hash__(self): # $ Alert # should use __hash__=None rather than stub implementation to make class unhashable
|
||||
raise NotImplementedError()
|
||||
|
||||
class B:
|
||||
def __sub__(self, other): # $ Alert # should return NotImplemented instead
|
||||
if not isinstance(other,B):
|
||||
raise TypeError()
|
||||
return self
|
||||
|
||||
def __add__(self, other): # No alert - allow add to raise a TypeError, as it is sometimes used for sequence concatenation as well as arithmetic
|
||||
if not isinstance(other,B):
|
||||
raise TypeError()
|
||||
return self
|
||||
|
||||
def __setitem__(self, key, val): # No alert - allow setitem to raise arbitrary exceptions as they could be due to the value, rather than a LookupError relating to the key
|
||||
if val < 0:
|
||||
raise ValueError()
|
||||
|
||||
def __getitem__(self, key): # No alert - indexing method allowed to raise TypeError or subclasses of LookupError.
|
||||
if not isinstance(key, int):
|
||||
raise TypeError()
|
||||
if key < 0:
|
||||
raise KeyError()
|
||||
return 3
|
||||
|
||||
def __getattribute__(self, name):
|
||||
if name != "a":
|
||||
raise AttributeError()
|
||||
return 2
|
||||
|
||||
def __div__(self, other):
|
||||
if other == 0:
|
||||
raise ZeroDivisionError()
|
||||
return self
|
||||
|
||||
|
||||
class D:
|
||||
def __int__(self):
|
||||
return 2
|
||||
|
||||
class E(D):
|
||||
def __int__(self): # No alert - cast method may override to raise exception
|
||||
raise TypeError()
|
||||
@@ -1,3 +0,0 @@
|
||||
| protocols.py:98:5:98:33 | Function __getitem__ | Function always raises $@; raise LookupError instead | file://:Compiled Code:0:0:0:0 | builtin-class ZeroDivisionError | builtin-class ZeroDivisionError |
|
||||
| protocols.py:101:5:101:26 | Function __getattr__ | Function always raises $@; raise AttributeError instead | file://:Compiled Code:0:0:0:0 | builtin-class ZeroDivisionError | builtin-class ZeroDivisionError |
|
||||
| protocols.py:104:5:104:23 | Function __bool__ | Function always raises $@; raise TypeError instead | file://:Compiled Code:0:0:0:0 | builtin-class ZeroDivisionError | builtin-class ZeroDivisionError |
|
||||
@@ -1 +0,0 @@
|
||||
Functions/IncorrectRaiseInSpecialMethod.ql
|
||||
Reference in New Issue
Block a user