rocky / python-uncompyle6

A cross-version Python bytecode decompiler
GNU General Public License v3.0
3.74k stars 408 forks source link

Specific Python3.6 control structure decompiling fails #344

Closed davidhao3300 closed 2 years ago

davidhao3300 commented 3 years ago

Description

uncompyle6 appears to not understand a particular control flow in python 3.6 (works in python 3.8).

How to Reproduce

Run the following snippet in python 3.6 (simplified version of our problem code):

from io import StringIO
from uncompyle6.semantics.pysource import code_deparse
def failing():
    x = 1
    if x==1:
        if x == 1:
            if x == 1:
                x = 1
        else:
            x = 1
    else:
        x = 1

new_code_in = StringIO()
code_deparse(failing.__code__, out=new_code_in)
code = new_code_in.getvalue()
print(code)

Output:

Traceback (most recent call last):
  File "/home/ubuntu/strap/.venv36/lib/python3.6/site-packages/uncompyle6/semantics/pysource.py", line 2525, in build_ast
    ast = python_parser.parse(self.p, tokens, customize, code)
  File "/home/ubuntu/strap/.venv36/lib/python3.6/site-packages/uncompyle6/parser.py", line 628, in parse
    ast = p.parse(tokens)
  File "/home/ubuntu/strap/.venv36/lib/python3.6/site-packages/spark_parser/spark.py", line 501, in parse
    self.error(tokens, i-1)
  File "/home/ubuntu/strap/.venv36/lib/python3.6/site-packages/uncompyle6/parser.py", line 209, in error
    raise ParserError(err_token, err_token.offset, self.debug["reduce"])
uncompyle6.parser.ParserError: Parse error at or near `STORE_FAST' instruction at offset 42

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "test.py", line 15, in <module>
    code_deparse(failing.__code__, out=new_code_in)
  File "/home/ubuntu/strap/.venv36/lib/python3.6/site-packages/uncompyle6/semantics/pysource.py", line 2595, in code_deparse
    deparsed.ast = deparsed.build_ast(tokens, customize, co, isTopLevel=isTopLevel)
  File "/home/ubuntu/strap/.venv36/lib/python3.6/site-packages/uncompyle6/semantics/pysource.py", line 2528, in build_ast
    raise ParserError(e, tokens, self.p.debug['reduce'])
uncompyle6.semantics.parser_error.ParserError: --- This code section failed: ---

 L.   4         0  LOAD_CONST               1
                2  STORE_FAST               'x'

 L.   5         4  LOAD_FAST                'x'
                6  LOAD_CONST               1
                8  COMPARE_OP               ==
               10  POP_JUMP_IF_FALSE    40  'to 40'

 L.   6        12  LOAD_FAST                'x'
               14  LOAD_CONST               1
               16  COMPARE_OP               ==
               18  POP_JUMP_IF_FALSE    34  'to 34'

 L.   7        20  LOAD_FAST                'x'
               22  LOAD_CONST               1
               24  COMPARE_OP               ==
               26  POP_JUMP_IF_FALSE    38  'to 38'

 L.   8        28  LOAD_CONST               1
               30  STORE_FAST               'x'
               32  JUMP_ABSOLUTE        44  'to 44'
               34  ELSE                     '38'

 L.  10        34  LOAD_CONST               1
               36  STORE_FAST               'x'
             38_0  COME_FROM            26  '26'
               38  JUMP_FORWARD         44  'to 44'
               40  ELSE                     '44'

 L.  12        40  LOAD_CONST               1
               42  STORE_FAST               'x'
             44_0  COME_FROM            38  '38'

Parse error at or near `STORE_FAST' instruction at offset 42

The following control structures DO work in 3.6:

# Removes if > if > if
def passing():
    x = 1
    if x==1:
        if x == 1:
            x = 1
        else:
            x = 1
    else:
        x = 1
# Removes else
def passing2():
    x = 1
    if x==1:
        if x == 1:
            if x == 1:
                x = 1
        else:
            x = 1
# ADDS if > if > else
def passing3():
    x = 1
    if x==1:
        if x == 1:
            if x == 1:
                x = 1
            else:
                x = 1
        else:
            x = 1
    else:
        x = 1

Expected behavior

No error is thrown

Environment

Additional Environment or Context

N/A