mirror of
https://github.com/github/codeql.git
synced 2025-12-17 01:03:14 +01:00
Technically we still depend on points-to in that we still mention `PythonFunctionValue` and `ClassValue` in the query. However, we immediately move to working with the corresponding `Function` and `Class` AST nodes, and so we're not really using points-to. (The reason for doing things this way is that otherwise the `.toString()` for all of the alerts would change, which would make the diff hard to interpret. This way, it should be fairly simple to see which changes are actually relevant.) We do lose some precision when moving away from points-to, and this is reflected in the changes in the `.expected` file. In particular we no longer do complicated tracking of values, but rather look at the syntactic structure of the classes in question. This causes us to lose out on some results where a special method is defined elsewhere, and causes a single FP where a special method initially has the wrong signature, but is subsequently overwritten with a function with the correct signature. We also lose out on results having to do with default values, as these are now disabled. Finally, it was necessary to add special handling of methods marked with the `staticmethod` decorator, as these expect to receive fewer arguments. This was motivated by a MRVA run, where e.g. sympy showed a lot of examples along the lines of ``` @staticmethod def __abs__(): return ... ```
112 lines
2.0 KiB
Python
112 lines
2.0 KiB
Python
|
|
#Signature overridden wrong
|
|
|
|
class Base(object):
|
|
|
|
def ok1(self, arg1, arg2 = 2):
|
|
return arg1, arg2
|
|
|
|
def ok2(self, arg1, arg2 = 2):
|
|
return arg1, arg2
|
|
|
|
def grossly_wrong1(self, arg1, arg2):
|
|
return arg1, arg2
|
|
|
|
def grossly_wrong2(self, arg1, arg2):
|
|
return arg1, arg2
|
|
|
|
def strictly_wrong1(self, arg1, arg2 = 2):
|
|
return arg1, arg2
|
|
|
|
def strictly_wrong2(self, arg1, arg2 = 2):
|
|
return arg1, arg2
|
|
|
|
class Derived(Base):
|
|
|
|
def ok1(self, arg1, arg2 = 2):
|
|
return arg1, arg2
|
|
|
|
def ok2(self, arg1, arg2 = 2, arg3 = 3):
|
|
return arg1, arg2, arg3
|
|
|
|
def grossly_wrong1(self, arg1):
|
|
return arg1
|
|
|
|
def grossly_wrong2(self, arg1, arg2, arg3):
|
|
return arg1, arg2, arg3
|
|
|
|
def strictly_wrong1(self, arg1):
|
|
return arg1
|
|
|
|
def strictly_wrong2(self, arg1, arg2, arg3 = 3):
|
|
return arg1, arg2, arg3
|
|
|
|
#Special method signatures
|
|
|
|
class Special(object):
|
|
|
|
def __add__(self, x):
|
|
return self, x
|
|
|
|
def __pos__(self):
|
|
return self
|
|
|
|
def __str__(self):
|
|
return repr(self)
|
|
|
|
class WrongSpecials(object):
|
|
|
|
def __div__(self, x, y):
|
|
return self, x, y
|
|
|
|
def __mul__(self):
|
|
return self
|
|
|
|
def __neg__(self, other):
|
|
return self, other
|
|
|
|
def __exit__(self, arg0, arg1):
|
|
return arg0 == arg1
|
|
|
|
def __repr__():
|
|
return ""
|
|
|
|
def __add__(self, other="Unused default"):
|
|
return 4
|
|
|
|
@staticmethod
|
|
def __abs__():
|
|
return 42
|
|
|
|
class OKSpecials(object):
|
|
|
|
def __del__():
|
|
state = some_state()
|
|
|
|
def __del__(self):
|
|
use_the_state(state)
|
|
|
|
return __del__
|
|
|
|
__del__ = __del__()
|
|
|
|
__add__ = lambda x, y : do_add(x, y)
|
|
|
|
class NotOKSpecials(object):
|
|
|
|
__sub__ = lambda x : do_neg(x)
|
|
|
|
#Correctly overridden builtin method
|
|
class LoggingDict(dict):
|
|
|
|
def pop(self):
|
|
print("pop")
|
|
return dict.pop(self)
|
|
|
|
|
|
|
|
class MoreSpecialMethods:
|
|
@staticmethod
|
|
def __abs__():
|
|
return 42
|