wala / ML

Eclipse Public License 2.0
25 stars 17 forks source link

Missing decorated functions whose decorators simply return the function #190

Open khatchad opened 5 months ago

khatchad commented 5 months ago

Description

Related to https://github.com/wala/ML/issues/189.

Consider the following code:

import tensorflow as tf

def mama(fun):
    return fun

@mama
def raffi(x):
    assert isinstance(x, tf.Tensor)

raffi(tf.constant(1))

The function raffi() is missing from the CG.

Regression

Reverting 2a6e5226db8ffb9aa8a4fd5dde637a452b55bbb2 fixes the problem.

When there's no inner function in the decorator, somehow, visiting entire decorator doesn't work. Visiting just the internal decorator (the child) works. It would seem that the decorator is missing from the PA:

BB1
...
101   v244 = new <PythonLoader,Lscript tf2_test_decorated_method3.py/mama>@101<no information> [244=[mama]]
...
104   v4 = new <PythonLoader,Lscript tf2_test_decorated_method3.py/raffi>@104<no information> [4=[raffi]]
105   v249 = invokeFunction < PythonLoader, LCodeBody, do()LRoot; > v244 @105 exception:v250tf2_test_decorated_method3.py [1:0] -> [13:21] [244=[mama]]
BB2
106   v18 = invokeFunction < PythonLoader, LCodeBody, do()LRoot; > v249,v4 @106 exception:v251tf2_test_decorated_method3.py [1:0] -> [13:21] [18=[raffi]4=[raffi]]
...
BB3
111   v252 = invokeFunction < PythonLoader, LCodeBody, do()LRoot; > v18,v253 @111 exception:v258tf2_test_decorated_method3.py [13:0] -> [13:21] [18=[raffi]]
[Node: <Code body of function Lscript tf2_test_decorated_method3.py> Context: CallStringContext: [ com.ibm.wala.FakeRootClass.fakeRootMethod()V@2 ], v4] --> [SMIK:SITE_IN_NODE{<Code body of function Lscript tf2_test_decorated_method3.py>:Lscript tf2_test_decorated_method3.py/raffi in CallStringContext: [ com.ibm.wala.FakeRootClass.fakeRootMethod()V@2 ]}@creator:Node: <Code body of function Lscript tf2_test_decorated_method3.py> Context: CallStringContext: [ com.ibm.wala.FakeRootClass.fakeRootMethod()V@2 ]]

[Node: <Code body of function Lscript tf2_test_decorated_method3.py> Context: CallStringContext: [ com.ibm.wala.FakeRootClass.fakeRootMethod()V@2 ], v18] --> []

[Node: <Code body of function Lscript tf2_test_decorated_method3.py> Context: CallStringContext: [ com.ibm.wala.FakeRootClass.fakeRootMethod()V@2 ], v249] --> []
khatchad commented 5 months ago

If I put the fix back, we get:

BB1
...
101   v244 = new <PythonLoader,Lscript tf2_test_decorated_method3.py/mama>@101<no information> [244=[mama]]
...
104   v4 = new <PythonLoader,Lscript tf2_test_decorated_method3.py/raffi>@104<no information> [4=[raffi]]
105   v249 = invokeFunction < PythonLoader, LCodeBody, do()LRoot; > v244 @105 exception:v250tf2_test_decorated_method3.py [1:0] -> [13:21] [244=[mama]]
BB2
106   v18 = invokeFunction < PythonLoader, LCodeBody, do()LRoot; > v244,v4 @106 exception:v251tf2_test_decorated_method3.py [1:0] -> [13:21] [18=[raffi]244=[mama]4=[raffi]]
...
BB3
111   v252 = invokeFunction < PythonLoader, LCodeBody, do()LRoot; > v18,v253 @111 exception:v258tf2_test_decorated_method3.py [13:0] -> [13:21] [18=[raffi]]
[Node: <Code body of function Lscript tf2_test_decorated_method3.py> Context: CallStringContext: [ com.ibm.wala.FakeRootClass.fakeRootMethod()V@2 ], v4] --> [SMIK:SITE_IN_NODE{<Code body of function Lscript tf2_test_decorated_method3.py>:Lscript tf2_test_decorated_method3.py/raffi in CallStringContext: [ com.ibm.wala.FakeRootClass.fakeRootMethod()V@2 ]}@creator:Node: <Code body of function Lscript tf2_test_decorated_method3.py> Context: CallStringContext: [ com.ibm.wala.FakeRootClass.fakeRootMethod()V@2 ]]

[Node: <Code body of function Lscript tf2_test_decorated_method3.py> Context: CallStringContext: [ com.ibm.wala.FakeRootClass.fakeRootMethod()V@2 ], v18] --> [SMIK:SITE_IN_NODE{<Code body of function Lscript tf2_test_decorated_method3.py>:Lscript tf2_test_decorated_method3.py/raffi in CallStringContext: [ com.ibm.wala.FakeRootClass.fakeRootMethod()V@2 ]}@creator:Node: <Code body of function Lscript tf2_test_decorated_method3.py> Context: CallStringContext: [ com.ibm.wala.FakeRootClass.fakeRootMethod()V@2 ]]

[Node: <Code body of function Lscript tf2_test_decorated_method3.py> Context: CallStringContext: [ com.ibm.wala.FakeRootClass.fakeRootMethod()V@2 ], v249] --> []
khatchad commented 5 months ago

Something looks to be wrong with instruction 105. When there's an embedded function, I am seeing the variable point to it. Otherwise, it's blank.

khatchad commented 5 months ago

The crux of the problem is that this is the decorator:

callees of node mama : []

IR of node 4, context CallStringContext: [ script tf2_test_decorated_method3.py.do()LRoot;@105 ]
<Code body of function Lscript tf2_test_decorated_method3.py/mama>
CFG:
BB0[-1..-2]
    -> BB1
BB1[0..0]
    -> BB2
BB2[-1..-2]
Instructions:
BB0
BB1
0   return v2                                tf2_test_decorated_method3.py [5:4] -> [5:14] [2=[fun]]
BB2

Here's the call to the decorator:

105   v249 = invokeFunction < PythonLoader, LCodeBody, do()LRoot; > v244 @105 exception:v250tf2_test_decorated_method3.py [1:0] -> [13:21] [244=[mama]]

We don't pass it anything until later:

106   v18 = invokeFunction < PythonLoader, LCodeBody, do()LRoot; > v249,v4 @106 exception:v251tf2_test_decorated_method3.py [1:0] -> [13:21] [18=[raffi]4=[raffi]]

But we have this:

[Node: <Code body of function Lscript tf2_test_decorated_method3.py> Context: CallStringContext: [ com.ibm.wala.FakeRootClass.fakeRootMethod()V@2 ], v249] --> []

But we do have this:

[Node: <Code body of function Lscript tf2_test_decorated_method3.py> Context: CallStringContext: [ com.ibm.wala.FakeRootClass.fakeRootMethod()V@2 ], v244] --> [SITE_IN_NODE{<Code body of function Lscript tf2_test_decorated_method3.py>:Lscript tf2_test_decorated_method3.py/mama in CallStringContext: [ com.ibm.wala.FakeRootClass.fakeRootMethod()V@2 ]}]

If the decorator returned itself (v1), it would work.

khatchad commented 5 months ago

This works in Jython 2, probably because decorators are not supported and consequently ignored there.