mirror of
https://github.com/github/codeql.git
synced 2025-12-24 04:36:35 +01:00
Python: Add test of __new__ handling
This commit is contained in:
16
python/ql/test/experimental/dataflow/calls/new_cls_param.py
Normal file
16
python/ql/test/experimental/dataflow/calls/new_cls_param.py
Normal file
@@ -0,0 +1,16 @@
|
||||
# We want to ensure that the __new__ method is considered a classmethod even though it
|
||||
# doesn't have a decorator. This means that the `cls` parameter should be considered a
|
||||
# reference to the class (or subclass), and not an instance of the class. We can detect
|
||||
# this from looking at the arguments passed in the `cls.foo` call. if we see a `self`
|
||||
# argument, this means it has correct behavior (because we're targeting a classmethod),
|
||||
# if there is no `self` argument, this means we've only considered `cls` to be a class
|
||||
# instance, since we don't want to pass that to the `cls` parameter of the classmethod `WithNewImpl.foo`.
|
||||
|
||||
class WithNewImpl(object):
|
||||
def __new__(cls):
|
||||
print("WithNewImpl.foo")
|
||||
cls.foo() # $ call=cls.foo() callType=CallTypeClassMethod MISSING: arg[self]=cls
|
||||
|
||||
@classmethod
|
||||
def foo(cls):
|
||||
print("WithNewImpl.foo")
|
||||
@@ -385,6 +385,32 @@ def test_potential_crosstalk_same_class(cond=True):
|
||||
SINK_F(objx2.x)
|
||||
|
||||
|
||||
class NewTest(object):
|
||||
def __new__(cls, arg):
|
||||
cls.foo = arg
|
||||
return super().__new__(cls) # $ unresolved_call=super().__new__(..)
|
||||
|
||||
@expects(4) # $ unresolved_call=expects(..) unresolved_call=expects(..)(..)
|
||||
def test__new__():
|
||||
# we want to make sure that we DON'T pass the synthetic pre-update node for
|
||||
# the class instance to __new__, like we do for __init__.
|
||||
nt = NewTest(SOURCE)
|
||||
# the __new__ implementation sets the foo attribute on THE CLASS itself. The
|
||||
# attribute lookup on the class instance will go to the class itself when the
|
||||
# attribute isn't defined on the class instance, so we will actually see `nt.foo`
|
||||
# contain the source, but the point of this test is that we should see identical
|
||||
# behavior between NewTest.foo and nt.foo, which we dont!
|
||||
#
|
||||
# Also note that we currently (October 2022) dont' model writes to classes very
|
||||
# well.
|
||||
|
||||
SINK(NewTest.foo) # $ MISSING: flow="SOURCE, l:-10 -> NewTest.foo"
|
||||
SINK(nt.foo) # $ flow="SOURCE, l:-11 -> nt.foo"
|
||||
|
||||
NewTest.foo = NONSOURCE
|
||||
SINK_F(NewTest.foo)
|
||||
SINK_F(nt.foo) # $ SPURIOUS: flow="SOURCE, l:-15 -> nt.foo"
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Global scope
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user