python-uncompyle6 icon indicating copy to clipboard operation
python-uncompyle6 copied to clipboard

`JUMP_ABSOLUTE` decompilation error

Open Berbe opened this issue 3 years ago • 0 comments

Description

Like in #310, I am running against a JUMP_ABSOLUTE error with a piece of bytecode written in Python 2.7, using uncompyle6 3.9.0a1 (source code from GitHub, current master branch):

class Test:
    elements = []

    def test--- This code section failed: ---

 L.   4         0  SETUP_LOOP           61  'to 64'
                3  LOAD_GLOBAL           0  'Test'
                6  LOAD_ATTR             1  'elements'
                9  GET_ITER
               10  FOR_ITER             50  'to 63'
               13  STORE_FAST            1  'element'

 L.   5        16  LOAD_FAST             1  'element'
               19  LOAD_ATTR             2  'a'
               22  POP_JUMP_IF_FALSE    10  'to 10'

 L.   6        25  LOAD_FAST             1  'element'
               28  LOAD_ATTR             3  'b'
             31_0  COME_FROM            22  '22'
               31  POP_JUMP_IF_FALSE    10  'to 10'

 L.   7        34  JUMP_FORWARD          3  'to 40'

 L.   9        37  CONTINUE             10  'to 10'
             40_0  COME_FROM            34  '34'

 L.  10        40  LOAD_FAST             1  'element'
               43  LOAD_ATTR             4  'c'
               46  POP_JUMP_IF_FALSE    60  'to 60'

 L.  11        49  LOAD_GLOBAL           5  'Hello'
               52  PRINT_ITEM
               53  PRINT_NEWLINE_CONT
               54  JUMP_ABSOLUTE        60  'to 60'
               57  JUMP_BACK            10  'to 10'
               60  JUMP_BACK            10  'to 10'
               63  POP_BLOCK
             64_0  COME_FROM             0  '0'

Parse error at or near `JUMP_ABSOLUTE' instruction at offset 54

How to Reproduce

Code
class Test():
    elements = []
    def test(self):
        for element in Test.elements:
            if element.a:
                if element.b:
                    pass
                else:
                    continue
                if element.c:
                    print Hello

Output Given

Output
# uncompyle6 version 3.9.0a1
# Python bytecode version base 2.7 (62211)
# Decompiled from: Python 3.9.2 (default, Feb 28 2021, 17:03:44)
# [GCC 10.2.1 20210110]
# Embedded file name: ./test.3.py
# Compiled at: 2022-09-20 22:47:05

-- Stacks of completed symbols:
START ::= |- stmts .
_come_froms ::= \e__come_froms . COME_FROM
_ifstmts_jump ::= \e_c_stmts_opt . JUMP_FORWARD come_froms
_ifstmts_jump ::= \e_c_stmts_opt JUMP_FORWARD . come_froms
_ifstmts_jump ::= c_stmts_opt . JUMP_FORWARD come_froms
_stmts ::= _stmts . stmt
_stmts ::= stmt .
and ::= expr . JUMP_IF_FALSE_OR_POP expr COME_FROM
and ::= expr . jmp_false expr \e_come_from_opt
and ::= expr . jmp_false expr come_from_opt
and ::= expr jmp_false . expr \e_come_from_opt
and ::= expr jmp_false . expr come_from_opt
and ::= expr jmp_false expr . come_from_opt
and ::= expr jmp_false expr \e_come_from_opt .
and ::= expr jmp_false expr come_from_opt .
assert ::= assert_expr . jmp_true LOAD_ASSERT RAISE_VARARGS_1
assert2 ::= assert_expr . jmp_true LOAD_ASSERT expr CALL_FUNCTION_1 RAISE_VARARGS_1
assert_expr ::= assert_expr_and .
assert_expr ::= expr .
assert_expr_and ::= assert_expr . jmp_false expr
assert_expr_and ::= assert_expr jmp_false . expr
assert_expr_and ::= assert_expr jmp_false expr .
assert_expr_or ::= assert_expr . jmp_true expr
assign ::= expr . DUP_TOP designList
assign ::= expr . store
assign2 ::= expr . expr ROT_TWO store store
assign3 ::= expr . expr expr ROT_THREE ROT_TWO store store store
attribute ::= expr . GET_ITER
attribute ::= expr . LOAD_ATTR
attribute ::= expr GET_ITER .
attribute ::= expr LOAD_ATTR .
aug_assign1 ::= expr . expr inplace_op ROT_FOUR STORE_SLICE+3
aug_assign1 ::= expr . expr inplace_op ROT_THREE STORE_SLICE+1
aug_assign1 ::= expr . expr inplace_op ROT_THREE STORE_SLICE+2
aug_assign1 ::= expr . expr inplace_op ROT_THREE STORE_SUBSCR
aug_assign1 ::= expr . expr inplace_op ROT_TWO STORE_SLICE+0
aug_assign1 ::= expr . expr inplace_op store
aug_assign2 ::= expr . DUP_TOP LOAD_ATTR expr inplace_op ROT_TWO STORE_ATTR
bin_op ::= expr . expr binary_operator
c_stmts ::= _stmts .
c_stmts ::= _stmts . lastc_stmt
c_stmts_opt ::= c_stmts .
call ::= expr . CALL_FUNCTION_0
call_stmt ::= expr . POP_TOP
classdefdeco1 ::= expr . classdefdeco1 CALL_FUNCTION_1
classdefdeco1 ::= expr . classdefdeco2 CALL_FUNCTION_1
come_from_opt ::= COME_FROM .
come_froms ::= COME_FROM .
come_froms ::= come_froms . COME_FROM
compare_chained ::= expr . compare_chained1 ROT_TWO POP_TOP \e__come_froms
compare_chained ::= expr . compare_chained1 ROT_TWO POP_TOP _come_froms
compare_single ::= expr . expr COMPARE_OP
continue ::= CONTINUE .
continues ::= _stmts . lastl_stmt continue
continues ::= _stmts lastl_stmt . continue
continues ::= continue .
delete ::= expr . DELETE_ATTR
delete_subscript ::= expr . expr DELETE_SUBSCR
else_suite ::= suite_stmts .
expr ::= LOAD_FAST .
expr ::= LOAD_GLOBAL .
expr ::= and .
expr ::= attribute .
expr ::= get_iter .
expr_jitop ::= expr . JUMP_IF_TRUE_OR_POP
expr_jt ::= expr . jmp_true
for ::= SETUP_LOOP . expr for_iter store for_block POP_BLOCK \e__come_froms
for ::= SETUP_LOOP . expr for_iter store for_block POP_BLOCK _come_froms
for ::= SETUP_LOOP expr . for_iter store for_block POP_BLOCK \e__come_froms
for ::= SETUP_LOOP expr . for_iter store for_block POP_BLOCK _come_froms
for ::= SETUP_LOOP expr for_iter . store for_block POP_BLOCK \e__come_froms
for ::= SETUP_LOOP expr for_iter . store for_block POP_BLOCK _come_froms
for ::= SETUP_LOOP expr for_iter store . for_block POP_BLOCK \e__come_froms
for ::= SETUP_LOOP expr for_iter store . for_block POP_BLOCK _come_froms
for_block ::= \e_l_stmts_opt . JUMP_BACK
for_block ::= \e_l_stmts_opt . _come_froms JUMP_BACK
for_block ::= \e_l_stmts_opt \e__come_froms . JUMP_BACK
for_block ::= l_stmts_opt . JUMP_BACK
for_block ::= l_stmts_opt . _come_froms JUMP_BACK
for_block ::= l_stmts_opt \e__come_froms . JUMP_BACK
for_iter ::= GET_ITER . COME_FROM FOR_ITER
for_iter ::= GET_ITER . FOR_ITER
for_iter ::= GET_ITER FOR_ITER .
forelsestmt ::= SETUP_LOOP . expr for_iter store for_block POP_BLOCK else_suite \e__come_froms
forelsestmt ::= SETUP_LOOP . expr for_iter store for_block POP_BLOCK else_suite _come_froms
forelsestmt ::= SETUP_LOOP expr . for_iter store for_block POP_BLOCK else_suite \e__come_froms
forelsestmt ::= SETUP_LOOP expr . for_iter store for_block POP_BLOCK else_suite _come_froms
forelsestmt ::= SETUP_LOOP expr for_iter . store for_block POP_BLOCK else_suite \e__come_froms
forelsestmt ::= SETUP_LOOP expr for_iter . store for_block POP_BLOCK else_suite _come_froms
forelsestmt ::= SETUP_LOOP expr for_iter store . for_block POP_BLOCK else_suite \e__come_froms
forelsestmt ::= SETUP_LOOP expr for_iter store . for_block POP_BLOCK else_suite _come_froms
genexpr_func ::= LOAD_FAST . FOR_ITER store comp_iter JUMP_BACK
get_iter ::= expr . GET_ITER
get_iter ::= expr GET_ITER .
if_exp ::= expr . jmp_false expr JUMP_ABSOLUTE expr
if_exp ::= expr . jmp_false expr JUMP_FORWARD expr COME_FROM
if_exp ::= expr jmp_false . expr JUMP_ABSOLUTE expr
if_exp ::= expr jmp_false . expr JUMP_FORWARD expr COME_FROM
if_exp ::= expr jmp_false expr . JUMP_ABSOLUTE expr
if_exp ::= expr jmp_false expr . JUMP_FORWARD expr COME_FROM
if_exp_lambda ::= expr . jmp_false expr return_if_lambda return_stmt_lambda LAMBDA_MARKER
if_exp_lambda ::= expr jmp_false . expr return_if_lambda return_stmt_lambda LAMBDA_MARKER
if_exp_lambda ::= expr jmp_false expr . return_if_lambda return_stmt_lambda LAMBDA_MARKER
if_exp_not ::= expr . jmp_true expr _jump expr COME_FROM
if_exp_not_lambda ::= expr . jmp_true expr return_if_lambda return_stmt_lambda LAMBDA_MARKER
if_exp_true ::= expr . JUMP_FORWARD expr COME_FROM
ifelsestmt ::= testexpr . c_stmts_opt JUMP_FORWARD else_suite come_froms
ifelsestmt ::= testexpr \e_c_stmts_opt . JUMP_FORWARD else_suite come_froms
ifelsestmt ::= testexpr \e_c_stmts_opt JUMP_FORWARD . else_suite come_froms
ifelsestmt ::= testexpr \e_c_stmts_opt JUMP_FORWARD else_suite . come_froms
ifelsestmt ::= testexpr \e_c_stmts_opt JUMP_FORWARD else_suite come_froms .
ifelsestmt ::= testexpr c_stmts_opt . JUMP_FORWARD else_suite come_froms
ifelsestmtl ::= testexpr . c_stmts_opt CONTINUE else_suitel
ifelsestmtl ::= testexpr . c_stmts_opt JUMP_BACK else_suitel
ifelsestmtl ::= testexpr \e_c_stmts_opt . CONTINUE else_suitel
ifelsestmtl ::= testexpr \e_c_stmts_opt . JUMP_BACK else_suitel
ifelsestmtl ::= testexpr c_stmts_opt . CONTINUE else_suitel
ifelsestmtl ::= testexpr c_stmts_opt . JUMP_BACK else_suitel
ifelsestmtr ::= testexpr . return_if_stmts COME_FROM returns
iflaststmtl ::= testexpr . c_stmts
iflaststmtl ::= testexpr . c_stmts_opt JUMP_BACK
iflaststmtl ::= testexpr \e_c_stmts_opt . JUMP_BACK
iflaststmtl ::= testexpr c_stmts .
iflaststmtl ::= testexpr c_stmts_opt . JUMP_BACK
ifstmt ::= testexpr . _ifstmts_jump
ifstmt ::= testexpr . return_if_stmts COME_FROM
ifstmt ::= testexpr . return_stmts COME_FROM
jmp_false ::= POP_JUMP_IF_FALSE .
l_stmts ::= _stmts .
l_stmts ::= _stmts . lastl_stmt
l_stmts ::= _stmts lastl_stmt .
l_stmts_opt ::= l_stmts .
lastl_stmt ::= iflaststmtl .
mkfuncdeco ::= expr . mkfuncdeco CALL_FUNCTION_1
mkfuncdeco ::= expr . mkfuncdeco0 CALL_FUNCTION_1
print_items_nl_stmt ::= expr . PRINT_ITEM \e_print_items_opt PRINT_NEWLINE_CONT
print_items_nl_stmt ::= expr . PRINT_ITEM print_items_opt PRINT_NEWLINE_CONT
print_items_nl_stmt ::= expr PRINT_ITEM . print_items_opt PRINT_NEWLINE_CONT
print_items_nl_stmt ::= expr PRINT_ITEM \e_print_items_opt . PRINT_NEWLINE_CONT
print_items_nl_stmt ::= expr PRINT_ITEM \e_print_items_opt PRINT_NEWLINE_CONT .
print_items_stmt ::= expr . PRINT_ITEM \e_print_items_opt
print_items_stmt ::= expr . PRINT_ITEM print_items_opt
print_items_stmt ::= expr PRINT_ITEM . print_items_opt
print_items_stmt ::= expr PRINT_ITEM \e_print_items_opt .
print_nl_to ::= expr . PRINT_NEWLINE_TO
print_to ::= expr . print_to_items POP_TOP
print_to_nl ::= expr . print_to_items PRINT_NEWLINE_TO
raise_stmt1 ::= expr . RAISE_VARARGS_1
raise_stmt2 ::= expr . expr RAISE_VARARGS_2
raise_stmt3 ::= expr . expr expr RAISE_VARARGS_3
ret_and ::= expr . JUMP_IF_FALSE_OR_POP return_expr_or_cond COME_FROM
ret_or ::= expr . JUMP_IF_TRUE_OR_POP return_expr_or_cond COME_FROM
return ::= return_expr . RETURN_VALUE
return_expr ::= expr .
return_expr_lambda ::= return_expr . RETURN_VALUE_LAMBDA
return_expr_lambda ::= return_expr . RETURN_VALUE_LAMBDA LAMBDA_MARKER
return_if_stmt ::= return_expr . RETURN_END_IF
return_if_stmts ::= _stmts . return_if_stmt
return_stmts ::= _stmts . return_stmt
returns ::= _stmts . return
slice0 ::= expr . DUP_TOP SLICE+0
slice0 ::= expr . SLICE+0
slice1 ::= expr . expr DUP_TOPX_2 SLICE+1
slice1 ::= expr . expr SLICE+1
slice2 ::= expr . expr DUP_TOPX_2 SLICE+2
slice2 ::= expr . expr SLICE+2
slice3 ::= expr . expr expr DUP_TOPX_3 SLICE+3
slice3 ::= expr . expr expr SLICE+3
stmt ::= continue .
stmt ::= ifelsestmt .
stmt ::= print_items_nl_stmt .
stmt ::= print_items_stmt .
store ::= STORE_FAST .
subscript ::= expr . expr BINARY_SUBSCR
subscript2 ::= expr . expr DUP_TOPX_2 BINARY_SUBSCR
suite_stmts ::= _stmts .
suite_stmts ::= continues .
testexpr ::= testfalse .
testfalse ::= expr . jmp_false
testfalse ::= expr jmp_false .
testtrue ::= expr . jmp_true
unary_convert ::= expr . UNARY_CONVERT
unary_not ::= expr . UNARY_NOT
unary_op ::= expr . unary_operator
while1elsestmt ::= SETUP_LOOP . l_stmts JUMP_BACK POP_BLOCK else_suitel COME_FROM
while1elsestmt ::= SETUP_LOOP . l_stmts JUMP_BACK else_suitel COME_FROM
while1stmt ::= SETUP_LOOP . l_stmts_opt CONTINUE COME_FROM
while1stmt ::= SETUP_LOOP . l_stmts_opt JUMP_BACK COME_FROM
while1stmt ::= SETUP_LOOP . l_stmts_opt JUMP_BACK POP_BLOCK COME_FROM
while1stmt ::= SETUP_LOOP . returns COME_FROM
while1stmt ::= SETUP_LOOP . returns pb_come_from
while1stmt ::= SETUP_LOOP \e_l_stmts_opt . CONTINUE COME_FROM
while1stmt ::= SETUP_LOOP \e_l_stmts_opt . JUMP_BACK COME_FROM
while1stmt ::= SETUP_LOOP \e_l_stmts_opt . JUMP_BACK POP_BLOCK COME_FROM
whileelsestmt ::= SETUP_LOOP . testexpr \e_l_stmts_opt JUMP_BACK POP_BLOCK else_suitel COME_FROM
whileelsestmt ::= SETUP_LOOP . testexpr l_stmts_opt JUMP_BACK POP_BLOCK else_suitel COME_FROM
whilestmt ::= SETUP_LOOP . testexpr \e_l_stmts_opt JUMP_BACK JUMP_BACK POP_BLOCK \e__come_froms
whilestmt ::= SETUP_LOOP . testexpr \e_l_stmts_opt JUMP_BACK JUMP_BACK POP_BLOCK _come_froms
whilestmt ::= SETUP_LOOP . testexpr \e_l_stmts_opt JUMP_BACK POP_BLOCK \e__come_froms
whilestmt ::= SETUP_LOOP . testexpr \e_l_stmts_opt JUMP_BACK POP_BLOCK _come_froms
whilestmt ::= SETUP_LOOP . testexpr l_stmts_opt JUMP_BACK JUMP_BACK POP_BLOCK \e__come_froms
whilestmt ::= SETUP_LOOP . testexpr l_stmts_opt JUMP_BACK JUMP_BACK POP_BLOCK _come_froms
whilestmt ::= SETUP_LOOP . testexpr l_stmts_opt JUMP_BACK POP_BLOCK \e__come_froms
whilestmt ::= SETUP_LOOP . testexpr l_stmts_opt JUMP_BACK POP_BLOCK _come_froms
whilestmt ::= SETUP_LOOP . testexpr returns \e__come_froms POP_BLOCK COME_FROM
whilestmt ::= SETUP_LOOP . testexpr returns _come_froms POP_BLOCK COME_FROM
with ::= expr . SETUP_WITH POP_TOP \e_suite_stmts_opt POP_BLOCK LOAD_CONST COME_FROM_WITH WITH_CLEANUP END_FINALLY
with ::= expr . SETUP_WITH POP_TOP suite_stmts_opt POP_BLOCK LOAD_CONST COME_FROM_WITH WITH_CLEANUP END_FINALLY
withasstmt ::= expr . SETUP_WITH store \e_suite_stmts_opt POP_BLOCK LOAD_CONST COME_FROM_WITH WITH_CLEANUP END_FINALLY
withasstmt ::= expr . SETUP_WITH store suite_stmts_opt POP_BLOCK LOAD_CONST COME_FROM_WITH WITH_CLEANUP END_FINALLY
yield ::= expr . YIELD_VALUE
Instruction context:

 L.  11        49  LOAD_GLOBAL           5  'Hello'
                  52  PRINT_ITEM
                  53  PRINT_NEWLINE_CONT
->                54  JUMP_ABSOLUTE        60  'to 60'
                  57  JUMP_BACK            10  'to 10'
                  60  JUMP_BACK            10  'to 10'
                  63  POP_BLOCK


class Test:
    elements = []

    def test--- This code section failed: ---

 L.   4         0  SETUP_LOOP           61  'to 64'
                3  LOAD_GLOBAL           0  'Test'
                6  LOAD_ATTR             1  'elements'
                9  GET_ITER
               10  FOR_ITER             50  'to 63'
               13  STORE_FAST            1  'element'

 L.   5        16  LOAD_FAST             1  'element'
               19  LOAD_ATTR             2  'a'
               22  POP_JUMP_IF_FALSE    10  'to 10'

 L.   6        25  LOAD_FAST             1  'element'
               28  LOAD_ATTR             3  'b'
             31_0  COME_FROM            22  '22'
               31  POP_JUMP_IF_FALSE    10  'to 10'

 L.   7        34  JUMP_FORWARD          3  'to 40'

 L.   9        37  CONTINUE             10  'to 10'
             40_0  COME_FROM            34  '34'

 L.  10        40  LOAD_FAST             1  'element'
               43  LOAD_ATTR             4  'c'
               46  POP_JUMP_IF_FALSE    60  'to 60'

 L.  11        49  LOAD_GLOBAL           5  'Hello'
               52  PRINT_ITEM
               53  PRINT_NEWLINE_CONT
               54  JUMP_ABSOLUTE        60  'to 60'
               57  JUMP_BACK            10  'to 10'
               60  JUMP_BACK            10  'to 10'
               63  POP_BLOCK
             64_0  COME_FROM             0  '0'

Parse error at or near `JUMP_ABSOLUTE' instruction at offset 54

# file test.3.pyc
# Deparsing stopped due to parse error

Additional information

If pass is replaced with print Foo, the error changes to the line of LOAD_FAST associated to element of element.c. It seems jumps pointers cache doesn't like this level of embedding inside condition blocks: if I move the instructions to a higher level, the problem vanishes. For instance, this code is fine:

Code
class Test():
    elements = []
    def test(self):
        for element in Test.elements:
            if element.a:
                pass
            else:
                continue
            if element.c:
                print Hello

Berbe avatar Sep 20 '22 20:09 Berbe